diff options
Diffstat (limited to 'client')
-rw-r--r-- | client/.cvsignore | 14 | ||||
-rw-r--r--[-rwxr-xr-x] | client/CMakeLists.txt | 103 | ||||
-rw-r--r-- | client/Makefile.am | 125 | ||||
-rw-r--r-- | client/async_example.c | 216 | ||||
-rw-r--r-- | client/client_priv.h | 51 | ||||
-rw-r--r-- | client/completion_hash.cc | 7 | ||||
-rw-r--r-- | client/get_password.c | 4 | ||||
-rw-r--r-- | client/my_readline.h | 5 | ||||
-rw-r--r-- | client/mysql.cc | 346 | ||||
-rw-r--r-- | client/mysql_plugin.c | 1206 | ||||
-rw-r--r-- | client/mysql_upgrade.c | 63 | ||||
-rw-r--r-- | client/mysqladmin.cc | 131 | ||||
-rw-r--r-- | client/mysqlbinlog.cc | 185 | ||||
-rw-r--r-- | client/mysqlcheck.c | 302 | ||||
-rw-r--r-- | client/mysqldump.c | 711 | ||||
-rw-r--r-- | client/mysqlimport.c | 70 | ||||
-rw-r--r-- | client/mysqlshow.c | 43 | ||||
-rw-r--r-- | client/mysqlslap.c | 89 | ||||
-rw-r--r-- | client/mysqltest.cc | 1735 | ||||
-rw-r--r-- | client/readline.cc | 8 | ||||
-rw-r--r-- | client/sql_string.cc.dontuse (renamed from client/sql_string.cc) | 92 | ||||
-rw-r--r-- | client/sql_string.h.dontuse (renamed from client/sql_string.h) | 33 |
22 files changed, 3927 insertions, 1612 deletions
diff --git a/client/.cvsignore b/client/.cvsignore deleted file mode 100644 index 54bbaed97f5..00000000000 --- a/client/.cvsignore +++ /dev/null @@ -1,14 +0,0 @@ -.deps -.libs -Makefile -Makefile.in -insert_test -mysql -mysql-test -mysql_test -mysqladmin -mysqldump -mysqlimport -mysqlshow -select_test -thread_test diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 2d51bc3fd0f..e4507f9c8ba 100755..100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -1,5 +1,4 @@ -# Copyright (c) 2006-2008 MySQL AB, 2009 Sun Microsystems, Inc. -# Use is subject to license terms. +# Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -12,63 +11,75 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -INCLUDE("${PROJECT_SOURCE_DIR}/win/mysql_manifest.cmake") +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# We use the "mysqlclient" library here just as safety, in case -# any of the clients here would go beyond the client API and access the -# Thread Local Storage directly. +INCLUDE_DIRECTORIES( + ${CMAKE_SOURCE_DIR}/include + ${ZLIB_INCLUDE_DIR} + ${SSL_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/libmysql + ${CMAKE_SOURCE_DIR}/regex + ${CMAKE_SOURCE_DIR}/sql + ${CMAKE_SOURCE_DIR}/strings + ${MY_READLINE_INCLUDE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) +ADD_DEFINITIONS(${SSL_DEFINES}) +MYSQL_ADD_EXECUTABLE(mysql completion_hash.cc mysql.cc readline.cc + ${CMAKE_SOURCE_DIR}/sql/sql_string.cc) +TARGET_LINK_LIBRARIES(mysql mysqlclient) +IF(UNIX) + TARGET_LINK_LIBRARIES(mysql ${MY_READLINE_LIBRARY}) + SET_TARGET_PROPERTIES(mysql PROPERTIES ENABLE_EXPORTS TRUE) +ENDIF(UNIX) -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include - ${CMAKE_SOURCE_DIR}/zlib - ${CMAKE_SOURCE_DIR}/extra/yassl/include - ${CMAKE_SOURCE_DIR}/libmysql - ${CMAKE_SOURCE_DIR}/regex - ${CMAKE_SOURCE_DIR}/sql - ${CMAKE_SOURCE_DIR}/strings - ${CMAKE_CURRENT_BINARY_DIR}) - -MYSQL_ADD_EXECUTABLE(mysql completion_hash.cc mysql.cc readline.cc sql_string.cc ../mysys/my_conio.c DESTINATION bin) -TARGET_LINK_LIBRARIES(mysql mysqlclient wsock32) - -MYSQL_ADD_EXECUTABLE(mysqltest mysqltest.cc DESTINATION bin) +MYSQL_ADD_EXECUTABLE(mysqltest mysqltest.cc COMPONENT Test) SET_SOURCE_FILES_PROPERTIES(mysqltest.cc PROPERTIES COMPILE_FLAGS "-DTHREADS") -TARGET_LINK_LIBRARIES(mysqltest mysqlclient mysys regex wsock32 dbug) +TARGET_LINK_LIBRARIES(mysqltest mysqlclient regex) +SET_TARGET_PROPERTIES(mysqltest PROPERTIES ENABLE_EXPORTS TRUE) -MYSQL_ADD_EXECUTABLE(mysqlcheck mysqlcheck.c DESTINATION bin) -TARGET_LINK_LIBRARIES(mysqlcheck mysqlclient wsock32) -MYSQL_ADD_EXECUTABLE(mysqldump mysqldump.c ../sql-common/my_user.c ../mysys/mf_getdate.c DESTINATION bin) -TARGET_LINK_LIBRARIES(mysqldump mysqlclient wsock32) +MYSQL_ADD_EXECUTABLE(mysqlcheck mysqlcheck.c) +TARGET_LINK_LIBRARIES(mysqlcheck mysqlclient) -MYSQL_ADD_EXECUTABLE(mysqlimport mysqlimport.c DESTINATION bin) -TARGET_LINK_LIBRARIES(mysqlimport mysqlclient wsock32) +MYSQL_ADD_EXECUTABLE(mysqldump mysqldump.c ../sql-common/my_user.c) +TARGET_LINK_LIBRARIES(mysqldump mysqlclient) -MYSQL_ADD_EXECUTABLE(mysql_upgrade mysql_upgrade.c DESTINATION bin) -TARGET_LINK_LIBRARIES(mysql_upgrade mysqlclient wsock32) +MYSQL_ADD_EXECUTABLE(mysqlimport mysqlimport.c) +TARGET_LINK_LIBRARIES(mysqlimport mysqlclient) + +MYSQL_ADD_EXECUTABLE(mysql_upgrade mysql_upgrade.c COMPONENT Server) +TARGET_LINK_LIBRARIES(mysql_upgrade mysqlclient) ADD_DEPENDENCIES(mysql_upgrade GenFixPrivs) -MYSQL_ADD_EXECUTABLE(mysqlshow mysqlshow.c DESTINATION bin) -TARGET_LINK_LIBRARIES(mysqlshow mysqlclient wsock32) +MYSQL_ADD_EXECUTABLE(mysqlshow mysqlshow.c) +TARGET_LINK_LIBRARIES(mysqlshow mysqlclient) + +MYSQL_ADD_EXECUTABLE(mysql_plugin mysql_plugin.c) +TARGET_LINK_LIBRARIES(mysql_plugin mysqlclient) -MYSQL_ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc - ../mysys/mf_tempdir.c - ../mysys/my_new.cc - ../mysys/my_bit.c - ../mysys/my_bitmap.c - ../mysys/my_vle.c - ../mysys/base64.c - ../mysys/checksum.c - DESTINATION bin) -TARGET_LINK_LIBRARIES(mysqlbinlog mysqlclient wsock32) +MYSQL_ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc) +TARGET_LINK_LIBRARIES(mysqlbinlog mysqlclient) -MYSQL_ADD_EXECUTABLE(mysqladmin mysqladmin.cc DESTINATION bin) -TARGET_LINK_LIBRARIES(mysqladmin mysqlclient wsock32) +MYSQL_ADD_EXECUTABLE(mysqladmin mysqladmin.cc) +TARGET_LINK_LIBRARIES(mysqladmin mysqlclient) -MYSQL_ADD_EXECUTABLE(mysqlslap mysqlslap.c DESTINATION bin) +MYSQL_ADD_EXECUTABLE(mysqlslap mysqlslap.c) SET_SOURCE_FILES_PROPERTIES(mysqlslap.c PROPERTIES COMPILE_FLAGS "-DTHREADS") -TARGET_LINK_LIBRARIES(mysqlslap mysqlclient mysys zlib wsock32 dbug) +TARGET_LINK_LIBRARIES(mysqlslap mysqlclient) + +# "WIN32" also covers 64 bit. "echo" is used in some files below "mysql-test/". +IF(WIN32) + MYSQL_ADD_EXECUTABLE(echo echo.c COMPONENT Junk) +ENDIF(WIN32) + +# async_example is just a code example, do not install it. +ADD_EXECUTABLE(async_example async_example.c) +TARGET_LINK_LIBRARIES(async_example mysqlclient) + +SET_TARGET_PROPERTIES (mysqlcheck mysqldump mysqlimport mysql_upgrade mysqlshow mysqlslap mysql_plugin +PROPERTIES HAS_CXX TRUE) +ADD_DEFINITIONS(-DHAVE_DLOPEN) -MYSQL_ADD_EXECUTABLE(echo echo.c COMPONENT Test) diff --git a/client/Makefile.am b/client/Makefile.am deleted file mode 100644 index f8a0a3f7139..00000000000 --- a/client/Makefile.am +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright (c) 2000, 2011, Oracle and/or its affiliates -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -# This file is public domain and comes with NO WARRANTY of any kind - -if THREAD_SAFE_CLIENT -LIBMYSQLCLIENT_LA = $(top_builddir)/libmysql_r/libmysqlclient_r.la -else -LIBMYSQLCLIENT_LA = $(top_builddir)/libmysql/libmysqlclient.la -endif - -INCLUDES = -I$(top_builddir)/include \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/regex \ - @ZLIB_INCLUDES@ \ - $(openssl_includes) - -LIBS = @CLIENT_LIBS@ - -LDADD= @CLIENT_EXTRA_LDFLAGS@ $(CLIENT_THREAD_LIBS) \ - $(top_builddir)/libmysql/libmysqlclient.la - -noinst_HEADERS = sql_string.h completion_hash.h my_readline.h \ - client_priv.h - -EXTRA_DIST = get_password.c CMakeLists.txt echo.c - -BUILT_SOURCES = link_sources - -CLEANFILES = $(BUILT_SOURCES) - -bin_PROGRAMS = mysql \ - mysqladmin \ - mysqlbinlog \ - mysqlcheck \ - mysqldump \ - mysqlimport \ - mysqlshow \ - mysqlslap \ - mysqltest \ - mysql_upgrade - -mysql_SOURCES = mysql.cc readline.cc sql_string.cc \ - completion_hash.cc -mysql_LDADD = @readline_link@ @TERMCAP_LIB@ \ - $(LDADD) $(CXXLDFLAGS) -mysqladmin_SOURCES = mysqladmin.cc - -mysqlbinlog_SOURCES = mysqlbinlog.cc \ - $(top_srcdir)/mysys/mf_tempdir.c \ - $(top_srcdir)/mysys/my_new.cc \ - $(top_srcdir)/mysys/my_bit.c \ - $(top_srcdir)/mysys/my_bitmap.c \ - $(top_srcdir)/mysys/my_vle.c \ - $(top_srcdir)/mysys/base64.c \ - $(top_srcdir)/mysys/checksum.c -mysqlbinlog_LDADD = $(LDADD) $(CXXLDFLAGS) - -mysqldump_SOURCES= mysqldump.c \ - my_user.c \ - $(top_srcdir)/mysys/mf_getdate.c - -mysqlimport_SOURCES= mysqlimport.c -mysqlimport_CFLAGS= -DTHREAD -UUNDEF_THREADS_HACK -mysqlimport_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \ - @CLIENT_EXTRA_LDFLAGS@ \ - $(LIBMYSQLCLIENT_LA) - -mysqlshow_SOURCES= mysqlshow.c - -mysqlslap_SOURCES= mysqlslap.c -mysqlslap_CFLAGS= -DTHREAD -UMYSQL_CLIENT_NO_THREADS -mysqlslap_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \ - @CLIENT_EXTRA_LDFLAGS@ \ - $(LIBMYSQLCLIENT_LA) - -mysqltest_SOURCES= mysqltest.cc -mysqltest_CXXFLAGS= -DTHREAD -UMYSQL_CLIENT_NO_THREADS -mysqltest_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \ - @CLIENT_EXTRA_LDFLAGS@ \ - $(top_builddir)/mysys/libmysys.a \ - $(LIBMYSQLCLIENT_LA) \ - $(top_builddir)/regex/libregex.la - -mysql_upgrade_SOURCES= mysql_upgrade.c \ - $(top_srcdir)/mysys/my_getpagesize.c - -# Fix for mit-threads -DEFS = -DMYSQL_CLIENT_NO_THREADS \ - -DDEFAULT_MYSQL_HOME='"$(prefix)"' \ - -DMYSQL_DATADIR='"$(localstatedir)"' - -sql_src=log_event.h mysql_priv.h rpl_constants.h \ - rpl_utility.h rpl_tblmap.h rpl_tblmap.cc \ - log_event.cc my_decimal.h my_decimal.cc \ - log_event_old.h log_event_old.cc \ - rpl_record_old.h rpl_record_old.cc \ - rpl_utility.h rpl_utility.cc \ - sql_list.h rpl_filter.h sql_list.cc rpl_filter.cc -strings_src=decimal.c strings_def.h - -link_sources: - for f in $(sql_src) ; do \ - rm -f $$f; \ - @LN_CP_F@ $(top_srcdir)/sql/$$f $$f; \ - done; \ - for f in $(strings_src) ; do \ - rm -f $$f; \ - @LN_CP_F@ $(top_srcdir)/strings/$$f $$f; \ - done; \ - rm -f my_user.c; \ - @LN_CP_F@ $(top_srcdir)/sql-common/my_user.c my_user.c; - echo timestamp > link_sources; diff --git a/client/async_example.c b/client/async_example.c new file mode 100644 index 00000000000..ccb60950904 --- /dev/null +++ b/client/async_example.c @@ -0,0 +1,216 @@ +/* + Copyright 2011 Kristian Nielsen and Monty Program Ab. + + This file is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this. If not, see <http://www.gnu.org/licenses/>. +*/ + + +#ifndef __WIN__ +#include <poll.h> +#else +#include <WinSock2.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <mysql.h> + +#define SL(s) (s), sizeof(s) + +static const char *my_groups[]= { "client", NULL }; + +static int +wait_for_mysql(MYSQL *mysql, int status) +{ +#ifdef __WIN__ + fd_set rs, ws, es; + int res; + struct timeval tv, *timeout; + my_socket s= mysql_get_socket(mysql); + FD_ZERO(&rs); + FD_ZERO(&ws); + FD_ZERO(&es); + if (status & MYSQL_WAIT_READ) + FD_SET(s, &rs); + if (status & MYSQL_WAIT_WRITE) + FD_SET(s, &ws); + if (status & MYSQL_WAIT_EXCEPT) + FD_SET(s, &es); + if (status & MYSQL_WAIT_TIMEOUT) + { + tv.tv_sec= mysql_get_timeout_value(mysql); + tv.tv_usec= 0; + timeout= &tv; + } + else + timeout= NULL; + res= select(1, &rs, &ws, &es, timeout); + if (res == 0) + return MYSQL_WAIT_TIMEOUT; + else if (res == SOCKET_ERROR) + { + /* + In a real event framework, we should handle errors and re-try the select. + */ + return MYSQL_WAIT_TIMEOUT; + } + else + { + int status= 0; + if (FD_ISSET(s, &rs)) + status|= MYSQL_WAIT_READ; + if (FD_ISSET(s, &ws)) + status|= MYSQL_WAIT_WRITE; + if (FD_ISSET(s, &es)) + status|= MYSQL_WAIT_EXCEPT; + return status; + } +#else + struct pollfd pfd; + int timeout; + int res; + + pfd.fd= mysql_get_socket(mysql); + pfd.events= + (status & MYSQL_WAIT_READ ? POLLIN : 0) | + (status & MYSQL_WAIT_WRITE ? POLLOUT : 0) | + (status & MYSQL_WAIT_EXCEPT ? POLLPRI : 0); + if (status & MYSQL_WAIT_TIMEOUT) + timeout= 1000*mysql_get_timeout_value(mysql); + else + timeout= -1; + res= poll(&pfd, 1, timeout); + if (res == 0) + return MYSQL_WAIT_TIMEOUT; + else if (res < 0) + { + /* + In a real event framework, we should handle EINTR and re-try the poll. + */ + return MYSQL_WAIT_TIMEOUT; + } + else + { + int status= 0; + if (pfd.revents & POLLIN) + status|= MYSQL_WAIT_READ; + if (pfd.revents & POLLOUT) + status|= MYSQL_WAIT_WRITE; + if (pfd.revents & POLLPRI) + status|= MYSQL_WAIT_EXCEPT; + return status; + } +#endif +} + +static void +fatal(MYSQL *mysql, const char *msg) +{ + fprintf(stderr, "%s: %s\n", msg, mysql_error(mysql)); + exit(1); +} + +static void +doit(const char *host, const char *user, const char *password) +{ + int err; + MYSQL mysql, *ret; + MYSQL_RES *res; + MYSQL_ROW row; + int status; + + mysql_init(&mysql); + mysql_options(&mysql, MYSQL_OPT_NONBLOCK, 0); + mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "myapp"); + + /* Returns 0 when done, else flag for what to wait for when need to block. */ + status= mysql_real_connect_start(&ret, &mysql, host, user, password, NULL, + 0, NULL, 0); + while (status) + { + status= wait_for_mysql(&mysql, status); + status= mysql_real_connect_cont(&ret, &mysql, status); + } + + if (!ret) + fatal(&mysql, "Failed to mysql_real_connect()"); + + status= mysql_real_query_start(&err, &mysql, SL("SHOW STATUS")); + while (status) + { + status= wait_for_mysql(&mysql, status); + status= mysql_real_query_cont(&err, &mysql, status); + } + if (err) + fatal(&mysql, "mysql_real_query() returns error"); + + /* This method cannot block. */ + res= mysql_use_result(&mysql); + if (!res) + fatal(&mysql, "mysql_use_result() returns error"); + + for (;;) + { + status= mysql_fetch_row_start(&row, res); + while (status) + { + status= wait_for_mysql(&mysql, status); + status= mysql_fetch_row_cont(&row, res, status); + } + if (!row) + break; + printf("%s: %s\n", row[0], row[1]); + } + if (mysql_errno(&mysql)) + fatal(&mysql, "Got error while retrieving rows"); + mysql_free_result(res); + + /* + mysql_close() sends a COM_QUIT packet, and so in principle could block + waiting for the socket to accept the data. + In practise, for many applications it will probably be fine to use the + blocking mysql_close(). + */ + status= mysql_close_start(&mysql); + while (status) + { + status= wait_for_mysql(&mysql, status); + status= mysql_close_cont(&mysql, status); + } +} + +int +main(int argc, char *argv[]) +{ + int err; + + if (argc != 4) + { + fprintf(stderr, "Usage: %s <host> <user> <password>\n", argv[0]); + exit(1); + } + + err= mysql_library_init(argc, argv, (char **)my_groups); + if (err) + { + fprintf(stderr, "Fatal: mysql_library_init() returns error: %d\n", err); + exit(1); + } + + doit(argv[1], argv[2], argv[3]); + + mysql_library_end(); + + return 0; +} diff --git a/client/client_priv.h b/client/client_priv.h index d948fb7f98f..607bd3997c1 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -21,7 +21,6 @@ #include <my_sys.h> #include <m_string.h> #include <mysql.h> -#include <mysql_embed.h> #include <errmsg.h> #include <my_getopt.h> @@ -33,19 +32,10 @@ # endif #endif -/* Version numbers for deprecation messages */ -#define VER_CELOSIA "5.6" - -#define WARN_DEPRECATED(Ver,Old,New) \ - do { \ - printf("Warning: The option '%s' is deprecated and will be removed " \ - "in a future release. Please use %s instead.\n", (Old), (New)); \ - } while(0); - enum options_client { OPT_CHARSETS_DIR=256, OPT_DEFAULT_CHARSET, - OPT_PAGER, OPT_NOPAGER, OPT_TEE, OPT_NOTEE, + OPT_PAGER, OPT_TEE, OPT_LOW_PRIORITY, OPT_AUTO_REPAIR, OPT_COMPRESS, OPT_DROP, OPT_LOCKS, OPT_KEYWORDS, OPT_DELAYED, OPT_OPTIMIZE, OPT_FTB, OPT_LTB, OPT_ENC, OPT_O_ENC, OPT_ESC, OPT_TABLES, @@ -60,12 +50,9 @@ enum options_client OPT_SHARED_MEMORY_BASE_NAME, OPT_FRM, OPT_SKIP_OPTIMIZATION, OPT_COMPATIBLE, OPT_RECONNECT, OPT_DELIMITER, OPT_SECURE_AUTH, OPT_OPEN_FILES_LIMIT, OPT_SET_CHARSET, OPT_SERVER_ARG, - OPT_POSITION, OPT_STOP_POSITION, OPT_START_DATETIME, OPT_STOP_DATETIME, + OPT_STOP_POSITION, OPT_START_DATETIME, OPT_STOP_DATETIME, OPT_SIGINT_IGNORE, OPT_HEXBLOB, OPT_ORDER_BY_PRIMARY, OPT_COUNT, OPT_FLUSH_TABLES, -#ifdef HAVE_NDBCLUSTER_DB - OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, -#endif OPT_TRIGGERS, OPT_MYSQL_ONLY_PRINT, OPT_MYSQL_LOCK_DIRECTORY, @@ -73,7 +60,10 @@ enum options_client OPT_IMPORT_USE_THREADS, OPT_MYSQL_NUMBER_OF_QUERY, OPT_IGNORE_TABLE,OPT_INSERT_IGNORE,OPT_SHOW_WARNINGS,OPT_DROP_DATABASE, - OPT_TZ_UTC, OPT_AUTO_CLOSE, OPT_CREATE_SLAP_SCHEMA, + OPT_TZ_UTC, OPT_CREATE_SLAP_SCHEMA, + OPT_MYSQLDUMP_SLAVE_APPLY, + OPT_MYSQLDUMP_SLAVE_DATA, + OPT_MYSQLDUMP_INCLUDE_MASTER_HOST_PORT, OPT_SLAP_CSV, OPT_SLAP_CREATE_STRING, OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE, OPT_SLAP_AUTO_GENERATE_WRITE_NUM, OPT_SLAP_AUTO_GENERATE_ADD_AUTO, @@ -91,15 +81,36 @@ enum options_client OPT_SLAP_NO_DROP, OPT_MYSQL_REPLACE_INTO, OPT_BASE64_OUTPUT_MODE, OPT_SERVER_ID, OPT_FIX_TABLE_NAMES, OPT_FIX_DB_NAMES, OPT_SSL_VERIFY_SERVER_CERT, + OPT_AUTO_VERTICAL_OUTPUT, OPT_DEBUG_INFO, OPT_DEBUG_CHECK, OPT_COLUMN_TYPES, OPT_ERROR_LOG_FILE, OPT_WRITE_BINLOG, OPT_DUMP_DATE, + OPT_INIT_COMMAND, + OPT_PLUGIN_DIR, + OPT_DEFAULT_AUTH, OPT_ABORT_SOURCE_ON_ERROR, - OPT_FIRST_SLAVE, - OPT_ALL, OPT_REWRITE_DB, - OPT_PLUGIN_DIR, - OPT_DEFAULT_PLUGIN, OPT_REPORT_PROGRESS, OPT_SKIP_ANNOTATE_ROWS_EVENTS, OPT_MAX_CLIENT_OPTION /* should be always the last */ }; + +/** + First mysql version supporting the information schema. +*/ +#define FIRST_INFORMATION_SCHEMA_VERSION 50003 + +/** + Name of the information schema database. +*/ +#define INFORMATION_SCHEMA_DB_NAME "information_schema" + +/** + First mysql version supporting the performance schema. +*/ +#define FIRST_PERFORMANCE_SCHEMA_VERSION 50503 + +/** + Name of the performance schema database. +*/ +#define PERFORMANCE_SCHEMA_DB_NAME "performance_schema" + diff --git a/client/completion_hash.cc b/client/completion_hash.cc index cd0ea17dfaf..9ffb2082c06 100644 --- a/client/completion_hash.cc +++ b/client/completion_hash.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -11,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* Quick & light hash implementation for tab completion purposes * @@ -22,7 +22,6 @@ #include <my_global.h> #include <m_string.h> -#undef SAFEMALLOC // Speed things up #include <my_sys.h> #include "completion_hash.h" @@ -213,7 +212,7 @@ void completion_hash_clean(HashTable *ht) void completion_hash_free(HashTable *ht) { completion_hash_clean(ht); - my_free(ht->arBuckets, MYF(0)); + my_free(ht->arBuckets); } diff --git a/client/get_password.c b/client/get_password.c index c6653183f48..09d307b5553 100644 --- a/client/get_password.c +++ b/client/get_password.c @@ -23,10 +23,6 @@ #include <m_string.h> #include <m_ctype.h> -#if defined(HAVE_BROKEN_GETPASS) && !defined(HAVE_GETPASSPHRASE) -#undef HAVE_GETPASS -#endif - #ifdef HAVE_GETPASS #ifdef HAVE_PWD_H #include <pwd.h> diff --git a/client/my_readline.h b/client/my_readline.h index 30e59b613bc..11ace987b44 100644 --- a/client/my_readline.h +++ b/client/my_readline.h @@ -1,3 +1,6 @@ +#ifndef CLIENT_MY_READLINE_INCLUDED +#define CLIENT_MY_READLINE_INCLUDED + /* Copyright (c) 2000, 2011, Oracle and/or its affiliates @@ -35,3 +38,5 @@ extern LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file); extern LINE_BUFFER *batch_readline_command(LINE_BUFFER *buffer, char * str); extern char *batch_readline(LINE_BUFFER *buffer); extern void batch_readline_end(LINE_BUFFER *buffer); + +#endif /* CLIENT_MY_READLINE_INCLUDED */ diff --git a/client/mysql.cc b/client/mysql.cc index a811bacdab0..67878b36227 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -15,10 +15,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define COPYRIGHT_NOTICE "\ -This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ -and you are welcome to modify and redistribute it under the GPL v2 license\n" - /* mysql command tool * Commands compatible with mSQL by David J. Hughes * @@ -60,11 +56,6 @@ static char *server_version= NULL; /* Array of options to pass to libemysqld */ #define MAX_SERVER_ARGS 64 -/* Version numbers for deprecation messages */ -#define VER_CELOSIA "5.6" - -void* sql_alloc(unsigned size); // Don't use mysqld alloc for these -void sql_element_free(void *ptr); #include "sql_string.h" extern "C" { @@ -97,9 +88,10 @@ extern "C" { #undef bcmp // Fix problem with new readline #if defined(__WIN__) #include <conio.h> -#elif !defined(__NETWARE__) +#else #include <readline/readline.h> #define HAVE_READLINE +#define USE_POPEN #endif } @@ -108,16 +100,12 @@ extern "C" { #define vidattr(A) {} // Can't get this to work #endif -#ifdef FN_NO_CASE_SENCE +#ifdef FN_NO_CASE_SENSE #define cmp_database(cs,A,B) my_strcasecmp((cs), (A), (B)) #else #define cmp_database(cs,A,B) strcmp((A),(B)) #endif -#if !defined(__WIN__) && !defined(__NETWARE__) && !defined(THREAD) -#define USE_POPEN -#endif - #include "completion_hash.h" #include <welcome_copyright_notice.h> // ORACLE_WELCOME_COPYRIGHT_NOTICE @@ -150,8 +138,9 @@ static my_bool ignore_errors=0,wait_flag=0,quick=0, vertical=0, line_numbers=1, column_names=1,opt_html=0, opt_xml=0,opt_nopager=1, opt_outfile=0, named_cmds= 0, tty_password= 0, opt_nobeep=0, opt_reconnect=1, - default_charset_used= 0, opt_secure_auth= 0, + opt_secure_auth= 0, default_pager_set= 0, opt_sigint_ignore= 0, + auto_vertical_output= 0, show_warnings= 0, executing_query= 0, ignore_spaces= 0, opt_progress_reports; static my_bool debug_info_flag, debug_check_flag, batch_abort_on_error; @@ -166,7 +155,8 @@ static int connect_flag=CLIENT_INTERACTIVE; static int interrupted_query= 0; static char *current_host,*current_db,*current_user=0,*opt_password=0, *current_prompt=0, *delimiter_str= 0, - *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; + *default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME, + *opt_init_command= 0; static char *histfile; static char *histfile_tmp; static String glob_buffer,old_buffer; @@ -176,7 +166,7 @@ static int wait_time = 5; static STATUS status; static ulong select_limit,max_join_size,opt_connect_timeout=0; static char mysql_charsets_dir[FN_REFLEN+1]; -static char *opt_plugin_dir= 0, *opt_default_auth; +static char *opt_plugin_dir= 0, *opt_default_auth= 0; static const char *xmlmeta[] = { "&", "&", "<", "<", @@ -196,6 +186,7 @@ static MEM_ROOT hash_mem_root; static uint prompt_counter; static char delimiter[16]= DEFAULT_DELIMITER; static uint delimiter_length= 1; +unsigned short terminal_width= 80; #ifdef HAVE_SMEM static char *shared_memory_base_name=0; @@ -249,6 +240,8 @@ static const char* construct_prompt(); static char *get_arg(char *line, my_bool get_next_arg); static void init_username(); static void add_int_to_prompt(int toadd); +static int get_result_width(MYSQL_RES *res); +static int get_field_disp_length(MYSQL_FIELD * field); #ifndef EMBEDDED_LIBRARY static uint last_progress_report_length= 0; static void report_progress(const MYSQL *mysql, uint stage, uint max_stage, @@ -471,7 +464,6 @@ static COMMANDS commands[] = { { "FORCE", 0, 0, 0, ""}, { "FOREIGN", 0, 0, 0, ""}, { "FOUND", 0, 0, 0, ""}, - { "FRAC_SECOND", 0, 0, 0, ""}, { "FROM", 0, 0, 0, ""}, { "FULL", 0, 0, 0, ""}, { "FULLTEXT", 0, 0, 0, ""}, @@ -640,10 +632,6 @@ static COMMANDS commands[] = { { "QUARTER", 0, 0, 0, ""}, { "QUERY", 0, 0, 0, ""}, { "QUICK", 0, 0, 0, ""}, - { "RAID0", 0, 0, 0, ""}, - { "RAID_CHUNKS", 0, 0, 0, ""}, - { "RAID_CHUNKSIZE", 0, 0, 0, ""}, - { "RAID_TYPE", 0, 0, 0, ""}, { "READ", 0, 0, 0, ""}, { "READS", 0, 0, 0, ""}, { "REAL", 0, 0, 0, ""}, @@ -716,7 +704,6 @@ static COMMANDS commands[] = { { "SQL_NO_CACHE", 0, 0, 0, ""}, { "SQL_SMALL_RESULT", 0, 0, 0, ""}, { "SQL_THREAD", 0, 0, 0, ""}, - { "SQL_TSI_FRAC_SECOND", 0, 0, 0, ""}, { "SQL_TSI_SECOND", 0, 0, 0, ""}, { "SQL_TSI_MINUTE", 0, 0, 0, ""}, { "SQL_TSI_HOUR", 0, 0, 0, ""}, @@ -907,6 +894,7 @@ static COMMANDS commands[] = { { "LAST_INSERT_ID", 0, 0, 0, ""}, { "ISSIMPLE", 0, 0, 0, ""}, { "LAST_DAY", 0, 0, 0, ""}, + { "LAST_VALUE", 0, 0, 0, ""}, { "LCASE", 0, 0, 0, ""}, { "LEAST", 0, 0, 0, ""}, { "LENGTH", 0, 0, 0, ""}, @@ -1084,6 +1072,10 @@ static void mysql_end_timer(ulong start_time,char *buff); static void nice_time(double sec,char *buff,bool part_second); extern "C" sig_handler mysql_end(int sig); extern "C" sig_handler handle_sigint(int sig); +#if defined(HAVE_TERMIOS_H) && defined(GWINSZ_IN_SYS_IOCTL) +static sig_handler window_resize(int sig); +#endif + int main(int argc,char *argv[]) { @@ -1134,7 +1126,11 @@ int main(int argc,char *argv[]) close(stdout_fileno_copy); /* Clean up dup(). */ } - load_defaults("my",load_default_groups,&argc,&argv); + if (load_defaults("my",load_default_groups,&argc,&argv)) + { + my_end(0); + exit(1); + } defaults_argv=argv; if (get_options(argc, (char **) argv)) { @@ -1166,8 +1162,8 @@ int main(int argc,char *argv[]) if (sql_connect(current_host,current_db,current_user,opt_password, opt_silent)) { - quick=1; // Avoid history - status.exit_status=1; + quick= 1; // Avoid history + status.exit_status= 1; mysql_end(-1); } if (!status.batch) @@ -1179,6 +1175,13 @@ int main(int argc,char *argv[]) signal(SIGINT, handle_sigint); // Catch SIGINT to clean up signal(SIGQUIT, mysql_end); // Catch SIGQUIT to clean up +#if defined(HAVE_TERMIOS_H) && defined(GWINSZ_IN_SYS_IOCTL) + /* Readline will call this if it installs a handler */ + signal(SIGWINCH, window_resize); + /* call the SIGWINCH handler to get the default term width */ + window_resize(0); +#endif + put_info("Welcome to the MariaDB monitor. Commands end with ; or \\g.", INFO_INFO); sprintf((char*) glob_buffer.ptr(), @@ -1208,7 +1211,7 @@ int main(int argc,char *argv[]) strncmp(link_name, "/dev/null", 10) == 0) { /* The .mysql_history file is a symlink to /dev/null, don't use it */ - my_free(histfile, MYF(MY_ALLOW_ZERO_PTR)); + my_free(histfile); histfile= 0; } } @@ -1269,23 +1272,23 @@ sig_handler mysql_end(int sig) glob_buffer.free(); old_buffer.free(); processed_prompt.free(); - my_free(server_version,MYF(MY_ALLOW_ZERO_PTR)); - my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); - my_free(opt_mysql_unix_port,MYF(MY_ALLOW_ZERO_PTR)); - my_free(histfile,MYF(MY_ALLOW_ZERO_PTR)); - my_free(histfile_tmp,MYF(MY_ALLOW_ZERO_PTR)); - my_free(current_db,MYF(MY_ALLOW_ZERO_PTR)); - my_free(current_host,MYF(MY_ALLOW_ZERO_PTR)); - my_free(current_user,MYF(MY_ALLOW_ZERO_PTR)); - my_free(full_username,MYF(MY_ALLOW_ZERO_PTR)); - my_free(part_username,MYF(MY_ALLOW_ZERO_PTR)); - my_free(default_prompt,MYF(MY_ALLOW_ZERO_PTR)); + my_free(server_version); + my_free(opt_password); + my_free(opt_mysql_unix_port); + my_free(histfile); + my_free(histfile_tmp); + my_free(current_db); + my_free(current_host); + my_free(current_user); + my_free(full_username); + my_free(part_username); + my_free(default_prompt); #ifdef HAVE_SMEM - my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); + my_free(shared_memory_base_name); #endif - my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR)); + my_free(current_prompt); while (embedded_server_arg_count > 1) - my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); + my_free(embedded_server_args[--embedded_server_arg_count]); mysql_server_end(); free_defaults(defaults_argv); my_end(my_end_arg); @@ -1357,6 +1360,16 @@ err: } +#if defined(HAVE_TERMIOS_H) && defined(GWINSZ_IN_SYS_IOCTL) +sig_handler window_resize(int sig) +{ + struct winsize window_size; + + if (ioctl(fileno(stdin), TIOCGWINSZ, &window_size) == 0) + terminal_width= window_size.ws_col; +} +#endif + static struct my_option my_long_options[] = { {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, @@ -1367,10 +1380,6 @@ static struct my_option my_long_options[] = "Abort 'source filename' operations in case of errors", &batch_abort_on_error, &batch_abort_on_error, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef __NETWARE__ - {"autoclose", OPT_AUTO_CLOSE, "Automatically 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, "Enable automatic rehashing. One doesn't need to use 'rehash' to get table " "and field completion, but startup and reconnecting may take a longer time. " @@ -1382,6 +1391,11 @@ static struct my_option my_long_options[] = "completion. This gives a quicker start of mysql and disables rehashing " "on reconnect.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"auto-vertical-output", OPT_AUTO_VERTICAL_OUTPUT, + "Automatically switch to vertical output mode if the result is wider " + "than the terminal width.", + &auto_vertical_output, &auto_vertical_output, 0, GET_BOOL, NO_ARG, 0, + 0, 0, 0, 0, 0}, {"batch", 'B', "Don't use history file. Disable interactive behavior. (Enables --silent.)", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -1433,21 +1447,18 @@ static struct my_option my_long_options[] = "is disabled by default.", &named_cmds, &named_cmds, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"no-named-commands", 'g', - "Named commands are disabled. Use \\* form only, or use named commands " - "only in the beginning of a line ending with a semicolon (;). Since " - "version 10.9, the client now starts with this option ENABLED by default. " - "Disable with '-G'. Long format commands still work from the first line. " - "WARNING: option deprecated; use --disable-named-commands instead.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"ignore-spaces", 'i', "Ignore space after function names.", &ignore_spaces, &ignore_spaces, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"init-command", OPT_INIT_COMMAND, + "SQL Command to execute when connecting to MySQL server. Will " + "automatically be re-executed when reconnecting.", + &opt_init_command, &opt_init_command, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"local-infile", OPT_LOCAL_INFILE, "Enable/disable LOAD DATA LOCAL INFILE.", - &opt_local_infile, - &opt_local_infile, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, + &opt_local_infile, &opt_local_infile, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"no-beep", 'b', "Turn off beep on error.", &opt_nobeep, - &opt_nobeep, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + &opt_nobeep, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"host", 'h', "Connect to host.", ¤t_host, ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"html", 'H', "Produce HTML output.", &opt_html, &opt_html, @@ -1456,7 +1467,7 @@ static struct my_option my_long_options[] = GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"line-numbers", OPT_LINE_NUMBERS, "Write line numbers for errors.", &line_numbers, &line_numbers, 0, GET_BOOL, - NO_ARG, 1, 0, 0, 0, 0, 0}, + NO_ARG, 1, 0, 0, 0, 0, 0}, {"skip-line-numbers", 'L', "Don't write line number for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"unbuffered", 'n', "Flush buffer after each query.", &unbuffered, @@ -1467,10 +1478,6 @@ static struct my_option my_long_options[] = {"skip-column-names", 'N', "Don't write column names in results.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"set-variable", 'O', - "Change the value of a variable. Please note that this option is " - "deprecated; you can set variables directly with --variable-name=value.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"sigint-ignore", OPT_SIGINT_IGNORE, "Ignore SIGINT (CTRL-C).", &opt_sigint_ignore, &opt_sigint_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -1486,10 +1493,6 @@ static struct my_option my_long_options[] = "This option does not work in batch mode. Disable with --disable-pager. " "This option is disabled by default.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"no-pager", OPT_NOPAGER, - "Disable pager and print to stdout. See interactive help (\\h) also. " - "WARNING: option deprecated; use --disable-pager instead.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"password", 'p', "Password to use when connecting to server. If password is not given it's asked from the tty.", @@ -1543,9 +1546,6 @@ static struct my_option my_long_options[] = "Does not work in batch mode. Disable with --disable-tee. " "This option is disabled by default.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"no-tee", OPT_NOTEE, "Disable outfile. See interactive help (\\h) also. " - "WARNING: Option deprecated; use --disable-tee instead.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef DONT_ALLOW_USER_CHANGE {"user", 'u', "User for login if not current user.", ¤t_user, ¤t_user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -1592,11 +1592,11 @@ static struct my_option my_long_options[] = &show_warnings, &show_warnings, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", - (uchar**) &opt_plugin_dir, (uchar**) &opt_plugin_dir, 0, + &opt_plugin_dir, &opt_plugin_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"default_auth", OPT_PLUGIN_DIR, + {"default_auth", OPT_DEFAULT_AUTH, "Default authentication client-side plugin to use.", - (uchar**) &opt_default_auth, (uchar**) &opt_default_auth, 0, + &opt_default_auth, &opt_default_auth, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -1604,11 +1604,6 @@ static struct my_option my_long_options[] = static void usage(int version) { - /* Divert all help information on NetWare to logger screen. */ -#ifdef __NETWARE__ -#define printf consoleprintf -#endif - #if defined(USE_LIBEDIT_INTERFACE) const char* readline= ""; #else @@ -1631,10 +1626,6 @@ static void usage(int version) my_print_help(my_long_options); print_defaults("my", load_default_groups); my_print_variables(my_long_options); - NETWARE_SET_SCREEN_MODE(1); -#ifdef __NETWARE__ -#undef printf -#endif } @@ -1643,18 +1634,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) { switch(optid) { -#ifdef __NETWARE__ - case OPT_AUTO_CLOSE: - setscreenmode(SCR_AUTOCLOSE_ON_EXIT); - break; -#endif case OPT_CHARSETS_DIR: strmake(mysql_charsets_dir, argument, sizeof(mysql_charsets_dir) - 1); charsets_dir = mysql_charsets_dir; break; - case OPT_DEFAULT_CHARSET: - default_charset_used= 1; - break; case OPT_DELIMITER: if (argument == disabled_my_option) { @@ -1688,11 +1671,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), else init_tee(argument); break; - case OPT_NOTEE: - WARN_DEPRECATED(VER_CELOSIA, "--no-tee", "--disable-tee"); - if (opt_outfile) - end_tee(); - break; case OPT_PAGER: if (argument == disabled_my_option) opt_nopager= 1; @@ -1711,10 +1689,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_nopager= 1; } break; - case OPT_NOPAGER: - WARN_DEPRECATED(VER_CELOSIA, "--no-pager", "--disable-pager"); - opt_nopager= 1; - break; case OPT_MYSQL_PROTOCOL: #ifndef EMBEDDED_LIBRARY opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, @@ -1758,25 +1732,19 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), if (!(status.line_buff= batch_readline_command(status.line_buff, argument))) return 1; break; - case 'g': - WARN_DEPRECATED(VER_CELOSIA, "-g, --no-named-commands", "--skip-named-commands"); - break; case 'o': if (argument == disabled_my_option) one_database= 0; else one_database= skip_updates= 1; break; - case 'O': - WARN_DEPRECATED(VER_CELOSIA, "-O, --set-variable", "--variable-name=value"); - break; case 'p': if (argument == disabled_my_option) argument= (char*) ""; // Don't require password if (argument) { char *start= argument; - my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); + my_free(opt_password); opt_password= my_strdup(argument, MYF(MY_FAE)); while (*argument) *argument++= 'x'; // Destroy argument if (*start) @@ -1818,11 +1786,13 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'V': usage(1); - exit(0); + status.exit_status= 0; + mysql_end(-1); case 'I': case '?': usage(0); - exit(0); + status.exit_status= 0; + mysql_end(-1); } return 0; } @@ -1869,10 +1839,6 @@ static int get_options(int argc, char **argv) opt_progress_reports= 0; } - if (strcmp(default_charset, charset_info->csname) && - !(charset_info= get_charset_by_csname(default_charset, - MY_CS_PRIMARY, MYF(MY_WME)))) - exit(1); if (argc > 1) { usage(0); @@ -1881,7 +1847,7 @@ static int get_options(int argc, char **argv) if (argc == 1) { skip_updates= 0; - my_free(current_db, MYF(MY_ALLOW_ZERO_PTR)); + my_free(current_db); current_db= my_strdup(*argv, MYF(MY_WME)); } if (tty_password) @@ -1902,10 +1868,6 @@ static int get_options(int argc, char **argv) static int read_and_execute(bool interactive) { -#if defined(__NETWARE__) - char linebuffer[254]; - String buffer; -#endif #if defined(__WIN__) String tmpbuf; String buffer; @@ -1950,18 +1912,8 @@ static int read_and_execute(bool interactive) if (opt_outfile && glob_buffer.is_empty()) fflush(OUTFILE); -#if defined(__WIN__) || defined(__NETWARE__) +#if defined(__WIN__) tee_fputs(prompt, stdout); -#if defined(__NETWARE__) - line=fgets(linebuffer, sizeof(linebuffer)-1, stdin); - /* Remove the '\n' */ - if (line) - { - char *p = strrchr(line, '\n'); - if (p != NULL) - *p = '\0'; - } -#else if (!tmpbuf.is_alloced()) tmpbuf.alloc(65535); tmpbuf.length(0); @@ -1982,12 +1934,11 @@ static int read_and_execute(bool interactive) */ if (line) line= buffer.c_ptr(); -#endif /* __NETWARE__ */ #else if (opt_outfile) fputs(prompt, OUTFILE); line= readline(prompt); -#endif /* defined(__WIN__) || defined(__NETWARE__) */ +#endif /* defined(__WIN__) */ /* When Ctrl+d or Ctrl+z is pressed, the line may be NULL on some OS @@ -2040,10 +1991,8 @@ static int read_and_execute(bool interactive) } } -#if defined(__WIN__) || defined(__NETWARE__) - buffer.free(); -#endif #if defined(__WIN__) + buffer.free(); tmpbuf.free(); #endif @@ -2392,8 +2341,10 @@ static bool add_line(String &buffer,char *line,char *in_string, #ifdef HAVE_READLINE +C_MODE_START static char *new_command_generator(const char *text, int); -extern "C" char **new_mysql_completion (const char *text, int start, int end); +static char **new_mysql_completion(const char *text, int start, int end); +C_MODE_END /* Tell the GNU Readline library how to complete. We want to try to complete @@ -2525,9 +2476,9 @@ static void initialize_readline (char *name) array of matches, or NULL if there aren't any. */ -char **new_mysql_completion (const char *text, - int start __attribute__((unused)), - int end __attribute__((unused))) +static char **new_mysql_completion(const char *text, + int start __attribute__((unused)), + int end __attribute__((unused))) { if (!status.batch && !quick) #if defined(USE_NEW_READLINE_INTERFACE) @@ -2781,7 +2732,7 @@ static int reconnect(void) } if (!connected) return put_info("Can't connect to the server\n",INFO_ERROR); - my_free(server_version,MYF(MY_ALLOW_ZERO_PTR)); + my_free(server_version); server_version= 0; /* purecov: end */ return 0; @@ -2795,7 +2746,7 @@ static void get_current_db() if (one_database) return; - my_free(current_db, MYF(MY_ALLOW_ZERO_PTR)); + my_free(current_db); current_db= NULL; /* In case of error below current_db will be NULL */ if (!mysql_query(&mysql, "SELECT DATABASE()") && @@ -2971,7 +2922,7 @@ com_help(String *buffer __attribute__((unused)), } put_info("\nGeneral information about MariaDB can be found at\n" - "http://askmonty.org/wiki/index.php/Manual:Contents\n", INFO_INFO); + "http://mariadb.org\n", INFO_INFO); put_info("List of all MySQL commands:", INFO_INFO); if (!named_cmds) put_info("Note that all text commands must be first on line and end with ';'",INFO_INFO); @@ -3021,7 +2972,6 @@ com_charset(String *buffer __attribute__((unused)), char *line) charset_info= new_cs; mysql_set_character_set(&mysql, charset_info->csname); default_charset= (char *)charset_info->csname; - default_charset_used= 1; put_info("Charset changed", INFO_INFO); } else put_info("Charset is not found", INFO_INFO); @@ -3149,7 +3099,7 @@ com_go(String *buffer,char *line __attribute__((unused))) print_table_data_html(result); else if (opt_xml) print_table_data_xml(result); - else if (vertical) + else if (vertical || (auto_vertical_output && (terminal_width < get_result_width(result)))) print_table_data_vertically(result); else if (opt_silent && verbose <= 2 && !output_tables) print_tab_data(result); @@ -3480,6 +3430,65 @@ print_table_data(MYSQL_RES *result) my_afree((uchar*) num_flag); } +/** + Return the length of a field after it would be rendered into text. + + This doesn't know or care about multibyte characters. Assume we're + using such a charset. We can't know that all of the upcoming rows + for this column will have bytes that each render into some fraction + of a character. It's at least possible that a row has bytes that + all render into one character each, and so the maximum length is + still the number of bytes. (Assumption 1: This can't be better + because we can never know the number of characters that the DB is + going to send -- only the number of bytes. 2: Chars <= Bytes.) + + @param field Pointer to a field to be inspected + + @returns number of character positions to be used, at most +*/ +static int get_field_disp_length(MYSQL_FIELD *field) +{ + uint length= column_names ? field->name_length : 0; + + if (quick) + length= max(length, field->length); + else + length= max(length, field->max_length); + + if (length < 4 && !IS_NOT_NULL(field->flags)) + length= 4; /* Room for "NULL" */ + + return length; +} + +/** + For a new result, return the max number of characters that any + upcoming row may return. + + @param result Pointer to the result to judge + + @returns The max number of characters in any row of this result +*/ +static int get_result_width(MYSQL_RES *result) +{ + unsigned int len= 0; + MYSQL_FIELD *field; + MYSQL_FIELD_OFFSET offset; + +#ifndef DBUG_OFF + offset= mysql_field_tell(result); + DBUG_ASSERT(offset == 0); +#else + offset= 0; +#endif + + while ((field= mysql_fetch_field(result)) != NULL) + len+= get_field_disp_length(field) + 3; /* plus bar, space, & final space */ + + (void) mysql_field_seek(result, offset); + + return len + 1; /* plus final bar. */ +} static void tee_print_sized_data(const char *data, unsigned int data_length, unsigned int total_bytes_to_send, bool right_justified) @@ -3962,8 +3971,6 @@ static int com_quit(String *buffer __attribute__((unused)), char *line __attribute__((unused))) { - /* let the screen auto close on a normal shutdown */ - NETWARE_SET_SCREEN_MODE(SCR_AUTOCLOSE_ON_EXIT); status.exit_status=0; return 1; } @@ -4041,12 +4048,12 @@ com_connect(String *buffer, char *line) tmp= get_arg(buff, 0); if (tmp && *tmp) { - my_free(current_db, MYF(MY_ALLOW_ZERO_PTR)); + my_free(current_db); current_db= my_strdup(tmp, MYF(MY_WME)); tmp= get_arg(buff, 1); if (tmp) { - my_free(current_host,MYF(MY_ALLOW_ZERO_PTR)); + my_free(current_host); current_host=my_strdup(tmp,MYF(MY_WME)); } } @@ -4231,7 +4238,7 @@ com_use(String *buffer __attribute__((unused)), char *line) if (mysql_select_db(&mysql,tmp)) return put_error(&mysql); } - my_free(current_db,MYF(MY_ALLOW_ZERO_PTR)); + my_free(current_db); current_db=my_strdup(tmp,MYF(MY_WME)); #ifdef HAVE_READLINE if (select_db > 1) @@ -4362,7 +4369,7 @@ char *mysql_authentication_dialog_ask(MYSQL *mysql, int type, s= get_tty_password(""); strnmov(buf, s, buf_len); buf[buf_len-1]= 0; - my_free(s, MYF(0)); + my_free(s); } else { @@ -4385,6 +4392,8 @@ sql_real_connect(char *host,char *database,char *user,char *password, mysql_close(&mysql); } mysql_init(&mysql); + if (opt_init_command) + mysql_options(&mysql, MYSQL_INIT_COMMAND, opt_init_command); if (opt_connect_timeout) { uint timeout=opt_connect_timeout; @@ -4397,7 +4406,7 @@ sql_real_connect(char *host,char *database,char *user,char *password, mysql_options(&mysql, MYSQL_SECURE_AUTH, (char *) &opt_secure_auth); if (using_opt_local_infile) mysql_options(&mysql,MYSQL_OPT_LOCAL_INFILE, (char*) &opt_local_infile); -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) if (opt_use_ssl) mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); @@ -4418,8 +4427,8 @@ sql_real_connect(char *host,char *database,char *user,char *password, select_limit,max_join_size); mysql_options(&mysql, MYSQL_INIT_COMMAND, init_command); } - if (default_charset_used) - mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); + + mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); if (opt_plugin_dir && *opt_plugin_dir) mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir); @@ -4428,8 +4437,8 @@ sql_real_connect(char *host,char *database,char *user,char *password, mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); if (!mysql_real_connect(&mysql, host, user, password, - database, opt_mysql_port, opt_mysql_unix_port, - connect_flag | CLIENT_MULTI_STATEMENTS)) + database, opt_mysql_port, opt_mysql_unix_port, + connect_flag | CLIENT_MULTI_STATEMENTS)) { if (!silent || (mysql_errno(&mysql) != CR_CONN_HOST_ERROR && @@ -4441,7 +4450,9 @@ sql_real_connect(char *host,char *database,char *user,char *password, } return -1; // Retryable } - + + charset_info= mysql.charset; + connected=1; #ifndef EMBEDDED_LIBRARY mysql.reconnect= debug_info_flag; // We want to know if this happens @@ -4529,12 +4540,12 @@ com_status(String *buffer __attribute__((unused)), mysql_free_result(result); } -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) if ((status_str= mysql_get_ssl_cipher(&mysql))) tee_fprintf(stdout, "SSL:\t\t\tCipher in use is %s\n", status_str); else -#endif /* HAVE_OPENSSL */ +#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */ tee_puts("SSL:\t\t\tNot in use", stdout); if (skip_updates) @@ -4764,7 +4775,6 @@ void tee_fprintf(FILE *file, const char *fmt, ...) { va_list args; - NETWARE_YIELD; va_start(args, fmt); (void) vfprintf(file, fmt, args); va_end(args); @@ -4780,7 +4790,6 @@ void tee_fprintf(FILE *file, const char *fmt, ...) void tee_fputs(const char *s, FILE *file) { - NETWARE_YIELD; fputs(s, file); if (opt_outfile) fputs(s, OUTFILE); @@ -4789,7 +4798,6 @@ void tee_fputs(const char *s, FILE *file) void tee_puts(const char *s, FILE *file) { - NETWARE_YIELD; fputs(s, file); fputc('\n', file); if (opt_outfile) @@ -4806,7 +4814,7 @@ void tee_putc(int c, FILE *file) putc(c, OUTFILE); } -#if defined(__WIN__) || defined(__NETWARE__) +#if defined(__WIN__) #include <time.h> #else #include <sys/times.h> @@ -4818,8 +4826,8 @@ void tee_putc(int c, FILE *file) static ulong start_timer(void) { -#if defined(__WIN__) || defined(__NETWARE__) - return clock(); +#if defined(__WIN__) + return clock(); #else struct tms tms_tmp; return times(&tms_tmp); @@ -5058,8 +5066,8 @@ static void add_int_to_prompt(int toadd) static void init_username() { - my_free(full_username,MYF(MY_ALLOW_ZERO_PTR)); - my_free(part_username,MYF(MY_ALLOW_ZERO_PTR)); + my_free(full_username); + my_free(part_username); MYSQL_RES *result; LINT_INIT(result); @@ -5078,7 +5086,7 @@ static int com_prompt(String *buffer __attribute__((unused)), { char *ptr=strchr(line, ' '); prompt_counter = 0; - my_free(current_prompt,MYF(MY_ALLOW_ZERO_PTR)); + my_free(current_prompt); current_prompt=my_strdup(ptr ? ptr+1 : default_prompt,MYF(MY_WME)); if (!ptr) tee_fprintf(stdout, "Returning to default PROMPT of %s\n", default_prompt); @@ -5088,18 +5096,6 @@ static int com_prompt(String *buffer __attribute__((unused)), } #ifndef EMBEDDED_LIBRARY -/* Keep sql_string library happy */ - -void *sql_alloc(size_t Size) -{ - return my_malloc(Size,MYF(MY_WME)); -} - -void sql_element_free(void *ptr) -{ - my_free(ptr,MYF(0)); -} - static void report_progress(const MYSQL *mysql, uint stage, uint max_stage, double progress, const char *proc_info, uint proc_info_length) diff --git a/client/mysql_plugin.c b/client/mysql_plugin.c new file mode 100644 index 00000000000..f4e3111b7b7 --- /dev/null +++ b/client/mysql_plugin.c @@ -0,0 +1,1206 @@ +/* + Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <m_string.h> +#include <mysql.h> +#include <my_getopt.h> +#include <my_dir.h> +#include <my_global.h> +#include <stdio.h> +#include <string.h> + + +#define SHOW_VERSION "1.0.0" +#define PRINT_VERSION do { printf("%s Ver %s Distrib %s\n", \ + my_progname, SHOW_VERSION, MYSQL_SERVER_VERSION); \ + } while(0) + +/* Global variables. */ +static uint my_end_arg= 0; +static uint opt_verbose=0; +static uint opt_no_defaults= 0; +static uint opt_print_defaults= 0; +static char *opt_datadir=0, *opt_basedir=0, + *opt_plugin_dir=0, *opt_plugin_ini=0, + *opt_mysqld=0, *opt_my_print_defaults=0; +static char bootstrap[FN_REFLEN]; + + +/* plugin struct */ +struct st_plugin +{ + const char *name; /* plugin name */ + const char *so_name; /* plugin so (library) name */ + const char *components[16]; /* components to load */ +} plugin_data; + + +/* Options */ +static struct my_option my_long_options[] = +{ + {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, + {"basedir", 'b', "The basedir for the server.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"datadir", 'd', "The datadir for the server.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin-dir", 'p', "The plugin dir for the server.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin-ini", 'i', "Read plugin information from configuration file " + "specified instead of from <plugin-dir>/<plugin_name>.ini.", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"no-defaults", 'n', "Do not read values from configuration file.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"print-defaults", 'P', "Show default values from configuration file.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"mysqld", 'm', "Path to mysqld executable. Example: /sbin/temp1/mysql/bin", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"my-print-defaults", 'f', "Path to my_print_defaults executable. " + "Example: /source/temp11/extra", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"verbose", 'v', + "More verbose output; you can use this multiple times to get even more " + "verbose output.", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, + NO_ARG, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} +}; + + +/* Methods */ +static int process_options(int argc, char *argv[], char *operation); +static int check_access(); +static int find_tool(const char *tool_name, char *tool_path); +static int find_plugin(char *tp_path); +static int build_bootstrap_file(char *operation, char *bootstrap); +static int dump_bootstrap_file(char *bootstrap_file); +static int bootstrap_server(char *server_path, char *bootstrap_file); + + +int main(int argc,char *argv[]) +{ + int error= 0; + char tp_path[FN_REFLEN]; + char server_path[FN_REFLEN]; + char operation[16]; + + MY_INIT(argv[0]); + sf_leaking_memory=1; /* don't report memory leaks on early exits */ + plugin_data.name= 0; // initialize name + + /* + The following operations comprise the method for enabling or disabling + a plugin. We begin by processing the command options then check the + directories specified for --datadir, --basedir, --plugin-dir, and + --plugin-ini (if specified). If the directories are Ok, we then look + for the mysqld executable and the plugin soname. Finally, we build a + bootstrap command file for use in bootstraping the server. + + If any step fails, the method issues an error message and the tool exits. + + 1) Parse, execute, and verify command options. + 2) Check access to directories. + 3) Look for mysqld executable. + 4) Look for the plugin. + 5) Build a bootstrap file with commands to enable or disable plugin. + + */ + if ((error= process_options(argc, argv, operation)) || + (error= check_access()) || + (error= find_tool("mysqld" FN_EXEEXT, server_path)) || + (error= find_plugin(tp_path)) || + (error= build_bootstrap_file(operation, bootstrap))) + goto exit; + + /* Dump the bootstrap file if --verbose specified. */ + if (opt_verbose && ((error= dump_bootstrap_file(bootstrap)))) + goto exit; + + /* Start the server in bootstrap mode and execute bootstrap commands */ + error= bootstrap_server(server_path, bootstrap); + +exit: + /* Remove file */ + my_delete(bootstrap, MYF(0)); + if (opt_verbose && error == 0) + { + printf("# Operation succeeded.\n"); + } + + my_end(my_end_arg); + exit(error ? 1 : 0); + return 0; /* No compiler warnings */ +} + + +/** + Get a temporary file name. + + @param[out] filename The file name of the temporary file + @param[in] ext An extension for the file (optional) + + @retval int error = 1, success = 0 +*/ + +static int make_tempfile(char *filename, const char *ext) +{ + int fd= 0; + + if ((fd=create_temp_file(filename, NullS, ext, O_CREAT | O_WRONLY, + MYF(MY_WME))) < 0) + { + fprintf(stderr, "ERROR: Cannot generate temporary file. Error code: %d.\n", + fd); + return 1; + } + my_close(fd, MYF(0)); + return 0; +} + + +/** + Get the value of an option from a string read from my_print_defaults output. + + @param[in] line The line (string) read from the file + @param[in] item The option to search for (e.g. --datadir) + + @returns NULL if not found, string containing value if found +*/ + +static char *get_value(char *line, const char *item) +{ + char *destination= 0; + int item_len= (int)strlen(item); + int line_len = (int)strlen(line); + + if ((strncasecmp(line, item, item_len) == 0)) + { + int start= 0; + char *s= 0; + + s = line + item_len + 1; + destination= my_strndup(s, line_len - start, MYF(MY_FAE)); + destination[line_len - item_len - 2]= 0; + } + return destination; +} + + +/** + Run a command in a shell. + + This function will attempt to execute the command specified by using the + popen() method to open a shell and execute the command passed and store the + output in a result file. If the --verbose option was specified, it will open + the result file and print the contents to stdout. + + @param[in] cmd The command to execute. + @param[in] mode The mode for popen() (e.g. "r", "w", "rw") + + @return int error code or 0 for success. +*/ + +static int run_command(char* cmd, const char *mode) +{ + char buf[512]= {0}; + FILE *res_file; + int error; + + if (!(res_file= popen(cmd, mode))) + return -1; + + if (opt_verbose) + { + while (fgets(buf, sizeof(buf), res_file)) + { + fprintf(stdout, "%s", buf); + } + } + error= pclose(res_file); + return error; +} + + +#ifdef __WIN__ +/** + Check to see if there are spaces in a path. + + @param[in] path The Windows path to examine. + + @retval int spaces found = 1, no spaces = 0 +*/ +static int has_spaces(const char *path) +{ + if (strchr(path, ' ') != NULL) + return 1; + return 0; +} + + +/** + Convert a Unix path to a Windows path. + + @param[in] path The Windows path to examine. + + @returns string containing path with / changed to \\ +*/ +static char *convert_path(const char *argument) +{ + /* Convert / to \\ to make Windows paths */ + char *winfilename= my_strdup(argument, MYF(MY_FAE)); + char *pos, *end; + int length= strlen(argument); + + for (pos= winfilename, end= pos+length ; pos < end ; pos++) + { + if (*pos == '/') + { + *pos= '\\'; + } + } + return winfilename; +} + + +/** + Add quotes if the path has spaces in it. + + @param[in] path The Windows path to examine. + + @returns string containing excaped quotes if spaces found in path +*/ +static char *add_quotes(const char *path) +{ + char windows_cmd_friendly[FN_REFLEN]; + + if (has_spaces(path)) + snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly), + "\"%s\"", path); + else + snprintf(windows_cmd_friendly, sizeof(windows_cmd_friendly), + "%s", path); + return my_strdup(windows_cmd_friendly, MYF(MY_FAE)); +} +#endif + + +/** + Get the default values from the my.cnf file. + + This method gets the default values for the following parameters: + + --datadir + --basedir + --plugin-dir + --plugin-ini + + These values are used if the user has not specified a value. + + @retval int error = 1, success = 0 +*/ + +static int get_default_values() +{ + char tool_path[FN_REFLEN]; + char defaults_cmd[FN_REFLEN]; + char defaults_file[FN_REFLEN]; + char line[FN_REFLEN]; + int error= 0; + int ret= 0; + FILE *file= 0; + + bzero(tool_path, FN_REFLEN); + if ((error= find_tool("my_print_defaults" FN_EXEEXT, tool_path))) + goto exit; + else + { + if ((error= make_tempfile(defaults_file, "txt"))) + goto exit; + +#ifdef __WIN__ + { + char *format_str= 0; + + if (has_spaces(tool_path) || has_spaces(defaults_file)) + format_str = "\"%s mysqld > %s\""; + else + format_str = "%s mysqld > %s"; + + snprintf(defaults_cmd, sizeof(defaults_cmd), format_str, + add_quotes(tool_path), add_quotes(defaults_file)); + if (opt_verbose) + { + printf("# my_print_defaults found: %s\n", tool_path); + } + } +#else + snprintf(defaults_cmd, sizeof(defaults_cmd), + "%s mysqld > %s", tool_path, defaults_file); +#endif + + /* Execute the command */ + if (opt_verbose) + { + printf("# Command: %s\n", defaults_cmd); + } + error= run_command(defaults_cmd, "r"); + if (error) + { + fprintf(stderr, "ERROR: my_print_defaults failed. Error code: %d.\n", + ret); + goto exit; + } + /* Now open the file and read the defaults we want. */ + file= fopen(defaults_file, "r"); + while (fgets(line, FN_REFLEN, file) != NULL) + { + char *value= 0; + + if ((opt_datadir == 0) && ((value= get_value(line, "--datadir")))) + { + opt_datadir= my_strdup(value, MYF(MY_FAE)); + } + if ((opt_basedir == 0) && ((value= get_value(line, "--basedir")))) + { + opt_basedir= my_strdup(value, MYF(MY_FAE)); + } + if ((opt_plugin_dir == 0) && ((value= get_value(line, "--plugin_dir")))) + { + opt_plugin_dir= my_strdup(value, MYF(MY_FAE)); + } + if ((opt_plugin_ini == 0) && ((value= get_value(line, "--plugin_ini")))) + { + opt_plugin_ini= my_strdup(value, MYF(MY_FAE)); + } + } + } +exit: + if (file) + { + fclose(file); + /* Remove file */ + my_delete(defaults_file, MYF(0)); + } + return error; +} + + +/** + Print usage. +*/ + +static void usage(void) +{ + PRINT_VERSION; + puts("Copyright (c) 2011, Oracle and/or its affiliates. " + "All rights reserved.\n"); + puts("Enable or disable plugins."); + printf("\nUsage: %s [options] <plugin> ENABLE|DISABLE\n\nOptions:\n", + my_progname); + my_print_help(my_long_options); + puts("\n"); +} + + +/** + Print the default values as read from the my.cnf file. + + This method displays the default values for the following parameters: + + --datadir + --basedir + --plugin-dir + --plugin-ini + +*/ + +static void print_default_values(void) +{ + printf("%s would have been started with the following arguments:\n", + my_progname); + get_default_values(); + if (opt_datadir) + { + printf("--datadir=%s ", opt_datadir); + } + if (opt_basedir) + { + printf("--basedir=%s ", opt_basedir); + } + if (opt_plugin_dir) + { + printf("--plugin_dir=%s ", opt_plugin_dir); + } + if (opt_plugin_ini) + { + printf("--plugin_ini=%s ", opt_plugin_ini); + } + if (opt_mysqld) + { + printf("--mysqld=%s ", opt_mysqld); + } + if (opt_my_print_defaults) + { + printf("--my_print_defaults=%s ", opt_my_print_defaults); + } + printf("\n"); +} + + +/** + Process the arguments and identify an option and store its value. + + @param[in] optid The single character shortcut for the argument. + @param[in] my_option Structure of legal options. + @param[in] argument The argument value to process. +*/ + +static my_bool +get_one_option(int optid, + const struct my_option *opt __attribute__((unused)), + char *argument) +{ + switch(optid) { + case 'n': + opt_no_defaults++; + break; + case 'P': + opt_print_defaults++; + print_default_values(); + break; + case 'v': + opt_verbose++; + break; + case 'V': + PRINT_VERSION; + exit(0); + break; + case '?': + case 'I': /* Info */ + usage(); + exit(0); + case 'd': + opt_datadir= my_strdup(argument, MYF(MY_FAE)); + break; + case 'b': + opt_basedir= my_strdup(argument, MYF(MY_FAE)); + break; + case 'p': + opt_plugin_dir= my_strdup(argument, MYF(MY_FAE)); + break; + case 'i': + opt_plugin_ini= my_strdup(argument, MYF(MY_FAE)); + break; + case 'm': + opt_mysqld= my_strdup(argument, MYF(MY_FAE)); + break; + case 'f': + opt_my_print_defaults= my_strdup(argument, MYF(MY_FAE)); + break; + } + return 0; +} + + +/** + Check to see if a file exists. + + @param[in] filename File to locate. + + @retval int file not found = 1, file found = 0 +*/ + +static int file_exists(char * filename) +{ + MY_STAT stat_arg; + + if (!my_stat(filename, &stat_arg, MYF(0))) + { + return 0; + } + return 1; +} + + +/** + Search a specific path and sub directory for a file name. + + @param[in] base_path Original path to use. + @param[in] tool_name Name of the tool to locate. + @param[in] subdir The sub directory to search. + @param[out] tool_path If tool found, return complete path. + + @retval int error = 1, success = 0 +*/ + +static int search_dir(const char * base_path, const char *tool_name, + const char *subdir, char *tool_path) +{ + char new_path[FN_REFLEN]; + char source_path[FN_REFLEN]; + + strcpy(source_path, base_path); + strcat(source_path, subdir); + fn_format(new_path, tool_name, source_path, "", MY_UNPACK_FILENAME); + if (file_exists(new_path)) + { + strcpy(tool_path, new_path); + return 1; + } + return 0; +} + + +/** + Search known common paths and sub directories for a file name. + + @param[in] base_path Original path to use. + @param[in] tool_name Name of the tool to locate. + @param[out] tool_path If tool found, return complete path. + + @retval int error = 1, success = 0 +*/ + +static int search_paths(const char *base_path, const char *tool_name, + char *tool_path) +{ + int i= 0; + + static const char *paths[]= { + "", "/share/", "/scripts/", "/bin/", "/sbin/", "/libexec/", + "/mysql/", "/sql/", + }; + for (i = 0 ; i < (int)array_elements(paths); i++) + { + if (search_dir(base_path, tool_name, paths[i], tool_path)) + { + return 1; + } + } + return 0; +} + + +/** + Read the plugin ini file. + + This function attempts to read the plugin config file from the plugin_dir + path saving the data in the the st_plugin structure. If the file is not + found or the file cannot be read, an error is generated. + + @retval int error = 1, success = 0 +*/ + +static int load_plugin_data(char *plugin_name, char *config_file) +{ + FILE *file_ptr; + char path[FN_REFLEN]; + char line[1024]; + char *reason= 0; + char *res; + int i= -1; + + if (opt_plugin_ini == 0) + { + fn_format(path, config_file, opt_plugin_dir, "", MYF(0)); + opt_plugin_ini= my_strdup(path, MYF(MY_FAE)); + } + if (!file_exists(opt_plugin_ini)) + { + reason= (char *)"File does not exist."; + goto error; + } + + file_ptr= fopen(opt_plugin_ini, "r"); + if (file_ptr == NULL) + { + reason= (char *)"Cannot open file."; + goto error; + } + + /* save name */ + plugin_data.name= my_strdup(plugin_name, MYF(MY_WME)); + + /* Read plugin components */ + while (i < 16) + { + res= fgets(line, sizeof(line), file_ptr); + /* strip /n */ + if (line[strlen(line)-1] == '\n') + { + line[strlen(line)-1]= '\0'; + } + if (res == NULL) + { + if (i < 1) + { + reason= (char *)"Bad format in plugin configuration file."; + fclose(file_ptr); + goto error; + } + break; + } + if ((line[0] == '#') || (line[0] == '\n')) // skip comment and blank lines + { + continue; + } + if (i == -1) // if first pass, read this line as so_name + { + /* Add proper file extension for soname */ + strcat(line, FN_SOEXT); + /* save so_name */ + plugin_data.so_name= my_strdup(line, MYF(MY_WME|MY_ZEROFILL)); + i++; + } + else + { + if (strlen(line) > 0) + { + plugin_data.components[i]= my_strdup(line, MYF(MY_WME)); + i++; + } + else + { + plugin_data.components[i]= NULL; + } + } + } + + fclose(file_ptr); + return 0; + +error: + fprintf(stderr, "ERROR: Cannot read plugin config file %s. %s\n", + plugin_name, reason); + return 1; +} + + +/** + Check the options for validity. + + This function checks the arguments for validity issuing the appropriate + error message if arguments are missing or invalid. On success, @operation + is set to either "ENABLE" or "DISABLE". + + @param[in] argc The number of arguments. + @param[in] argv The arguments. + @param[out] operation The operation chosen (enable|disable) + + @retval int error = 1, success = 0 +*/ + +static int check_options(int argc, char **argv, char *operation) +{ + int i= 0; // loop counter + int num_found= 0; // number of options found (shortcut loop) + char config_file[FN_REFLEN]; // configuration file name + char plugin_name[FN_REFLEN]; // plugin name + + /* Form prefix strings for the options. */ + const char *basedir_prefix = "--basedir="; + int basedir_len= strlen(basedir_prefix); + const char *datadir_prefix = "--datadir="; + int datadir_len= strlen(datadir_prefix); + const char *plugin_dir_prefix = "--plugin_dir="; + int plugin_dir_len= strlen(plugin_dir_prefix); + + strcpy(plugin_name, ""); + for (i = 0; i < argc && num_found < 5; i++) + { + + if (!argv[i]) + { + continue; + } + if ((strcasecmp(argv[i], "ENABLE") == 0) || + (strcasecmp(argv[i], "DISABLE") == 0)) + { + strcpy(operation, argv[i]); + num_found++; + } + else if ((strncasecmp(argv[i], basedir_prefix, basedir_len) == 0) && + !opt_basedir) + { + opt_basedir= my_strndup(argv[i]+basedir_len, + strlen(argv[i])-basedir_len, MYF(MY_FAE)); + num_found++; + } + else if ((strncasecmp(argv[i], datadir_prefix, datadir_len) == 0) && + !opt_datadir) + { + opt_datadir= my_strndup(argv[i]+datadir_len, + strlen(argv[i])-datadir_len, MYF(MY_FAE)); + num_found++; + } + else if ((strncasecmp(argv[i], plugin_dir_prefix, plugin_dir_len) == 0) && + !opt_plugin_dir) + { + opt_plugin_dir= my_strndup(argv[i]+plugin_dir_len, + strlen(argv[i])-plugin_dir_len, MYF(MY_FAE)); + num_found++; + } + /* read the plugin config file and check for match against argument */ + else + { + strcpy(plugin_name, argv[i]); + strcpy(config_file, argv[i]); + strcat(config_file, ".ini"); + } + } + + if (!opt_basedir) + { + fprintf(stderr, "ERROR: Missing --basedir option.\n"); + return 1; + } + + if (!opt_datadir) + { + fprintf(stderr, "ERROR: Missing --datadir option.\n"); + return 1; + } + + if (!opt_plugin_dir) + { + fprintf(stderr, "ERROR: Missing --plugin_dir option.\n"); + return 1; + } + /* If a plugin was specified, read the config file. */ + else if (strlen(plugin_name) > 0) + { + if (load_plugin_data(plugin_name, config_file)) + { + return 1; + } + if (strcasecmp(plugin_data.name, plugin_name) != 0) + { + fprintf(stderr, "ERROR: plugin name requested does not match config " + "file data.\n"); + return 1; + } + } + else + { + fprintf(stderr, "ERROR: No plugin specified.\n"); + return 1; + } + + if ((strlen(operation) == 0)) + { + fprintf(stderr, "ERROR: missing operation. Please specify either " + "'<plugin> ENABLE' or '<plugin> DISABLE'.\n"); + return 1; + } + + return 0; +} + + +/** + Parse, execute, and verify command options. + + This method handles all of the option processing including the optional + features for displaying data (--print-defaults, --help ,etc.) that do not + result in an attempt to ENABLE or DISABLE of a plugin. + + @param[in] arc Count of arguments + @param[in] argv Array of arguments + @param[out] operation Operation (ENABLE or DISABLE) + + @retval int error = 1, success = 0, exit program = -1 +*/ + +static int process_options(int argc, char *argv[], char *operation) +{ + int error= 0; + int i= 0; + + /* Parse and execute command-line options */ + if ((error= handle_options(&argc, &argv, my_long_options, get_one_option))) + goto exit; + + /* If the print defaults option used, exit. */ + if (opt_print_defaults) + { + error= -1; + goto exit; + } + + /* Add a trailing directory separator if not present */ + if (opt_basedir) + { + i= (int)strlength(opt_basedir); + if (opt_basedir[i-1] != FN_LIBCHAR || opt_basedir[i-1] != FN_LIBCHAR2) + { + char buff[FN_REFLEN]; + + strncpy(buff, opt_basedir, sizeof(buff) - 1); +#ifdef __WIN__ + strncat(buff, "/", sizeof(buff) - strlen(buff) - 1); +#else + strncat(buff, FN_DIRSEP, sizeof(buff) - strlen(buff) - 1); +#endif + buff[sizeof(buff) - 1]= 0; + my_delete(opt_basedir, MYF(0)); + opt_basedir= my_strdup(buff, MYF(MY_FAE)); + } + } + + /* + If the user did not specify the option to skip loading defaults from a + config file and the required options are not present or there was an error + generated when the defaults were read from the file, exit. + */ + if (!opt_no_defaults && ((error= get_default_values()))) + { + error= -1; + goto exit; + } + + /* + Check to ensure required options are present and validate the operation. + Note: this method also validates the plugin specified by attempting to + read a configuration file named <plugin_name>.ini from the --plugin-dir + or --plugin-ini location if the --plugin-ini option presented. + */ + strcpy(operation, ""); + if ((error = check_options(argc, argv, operation))) + { + goto exit; + } + + if (opt_verbose) + { + printf("# basedir = %s\n", opt_basedir); + printf("# plugin_dir = %s\n", opt_plugin_dir); + printf("# datadir = %s\n", opt_datadir); + printf("# plugin_ini = %s\n", opt_plugin_ini); + } + +exit: + return error; +} + + +/** + Check access + + This method checks to ensure all of the directories (opt_basedir, + opt_plugin_dir, opt_datadir, and opt_plugin_ini) are accessible by + the user. + + @retval int error = 1, success = 0 +*/ + +static int check_access() +{ + int error= 0; + + if ((error= my_access(opt_basedir, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access basedir at '%s'.\n", + opt_basedir); + goto exit; + } + if ((error= my_access(opt_plugin_dir, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access plugin_dir at '%s'.\n", + opt_plugin_dir); + goto exit; + } + if ((error= my_access(opt_datadir, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access datadir at '%s'.\n", + opt_datadir); + goto exit; + } + if (opt_plugin_ini && (error= my_access(opt_plugin_ini, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access plugin config file at '%s'.\n", + opt_plugin_ini); + goto exit; + } + if (opt_mysqld && (error= my_access(opt_mysqld, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access mysqld path '%s'.\n", + opt_mysqld); + goto exit; + } + if (opt_my_print_defaults && (error= my_access(opt_my_print_defaults, F_OK))) + { + fprintf(stderr, "ERROR: Cannot access my-print-defaults path '%s'.\n", + opt_my_print_defaults); + goto exit; + } + +exit: + return error; +} + + +/** + Locate the tool and form tool path. + + @param[in] tool_name Name of the tool to locate. + @param[out] tool_path If tool found, return complete path. + + @retval int error = 1, success = 0 +*/ + +static int find_tool(const char *tool_name, char *tool_path) +{ + int i= 0; + + const char *paths[]= { + opt_mysqld, opt_basedir, opt_my_print_defaults, "/usr", + "/usr/local/mysql", "/usr/sbin", "/usr/share", "/extra", "/extra/debug", + "/extra/release", "/bin", "/usr/bin", "/mysql/bin" + }; + for (i= 0; i < (int)array_elements(paths); i++) + { + if (paths[i] && (search_paths(paths[i], tool_name, tool_path))) + goto found; + } + fprintf(stderr, "WARNING: Cannot find %s.\n", tool_name); + return 1; +found: + if (opt_verbose) + printf("# Found tool '%s' as '%s'.\n", tool_name, tool_path); + return 0; +} + + +/** + Find the plugin library. + + This function attempts to use the @c plugin_dir option passed on the + command line to locate the plugin. + + @param[out] tp_path The actual path to plugin with FN_SOEXT applied. + + @retval int error = 1, success = 0 +*/ + +static int find_plugin(char *tp_path) +{ + /* Check for existance of plugin */ + fn_format(tp_path, plugin_data.so_name, opt_plugin_dir, "", MYF(0)); + if (!file_exists(tp_path)) + { + fprintf(stderr, "ERROR: The plugin library is missing or in a different" + " location.\n"); + return 1; + } + else if (opt_verbose) + { + printf("# Found plugin '%s' as '%s'\n", plugin_data.name, tp_path); + } + return 0; +} + + +/** + Build the boostrap file. + + Create a new file and populate it with SQL commands to ENABLE or DISABLE + the plugin via REPLACE and DELETE operations on the mysql.plugin table. + + param[in] operation The type of operation (ENABLE or DISABLE) + param[out] bootstrap A FILE* pointer + + @retval int error = 1, success = 0 +*/ + +static int build_bootstrap_file(char *operation, char *bootstrap) +{ + int error= 0; + FILE *file= 0; + + /* + Perform plugin operation : ENABLE or DISABLE + + The following creates a temporary bootstrap file and populates it with + the appropriate SQL commands for the operation. For ENABLE, REPLACE + statements are created. For DISABLE, DELETE statements are created. The + values for these statements are derived from the plugin_data read from the + <plugin_name>.ini configuration file. Once the file is built, a call to + mysqld is made in read only, bootstrap modes to read the SQL statements + and execute them. + + Note: Replace was used so that if a user loads a newer version of a + library with a different library name, the new library name is + used for symbols that match. + */ + if ((error= make_tempfile(bootstrap, "sql"))) + { + /* Fail if we cannot create a temporary file for the bootstrap commands. */ + fprintf(stderr, "ERROR: Cannot create bootstrap file.\n"); + goto exit; + } + if ((file= fopen(bootstrap, "w+")) == NULL) + { + fprintf(stderr, "ERROR: Cannot open bootstrap file for writing.\n"); + error= 1; + goto exit; + } + if (strcasecmp(operation, "enable") == 0) + { + int i= 0; + fprintf(file, "REPLACE INTO mysql.plugin VALUES "); + for (i= 0; i < (int)array_elements(plugin_data.components); i++) + { + /* stop when we read the end of the symbol list - marked with NULL */ + if (plugin_data.components[i] == NULL) + { + break; + } + if (i > 0) + { + fprintf(file, ", "); + } + fprintf(file, "('%s','%s')", + plugin_data.components[i], plugin_data.so_name); + } + fprintf(file, ";\n"); + if (opt_verbose) + { + printf("# Enabling %s...\n", plugin_data.name); + } + } + else + { + fprintf(file, + "DELETE FROM mysql.plugin WHERE dl = '%s';", plugin_data.so_name); + if (opt_verbose) + { + printf("# Disabling %s...\n", plugin_data.name); + } + } + +exit: + fclose(file); + return error; +} + + +/** + Dump bootstrap file. + + Read the contents of the bootstrap file and print it out. + + @param[in] bootstrap_file Name of bootstrap file to read + + @retval int error = 1, success = 0 +*/ + +static int dump_bootstrap_file(char *bootstrap_file) +{ + char *ret= 0; + int error= 0; + char query_str[512]; + FILE *file= 0; + + if ((file= fopen(bootstrap_file, "r")) == NULL) + { + fprintf(stderr, "ERROR: Cannot open bootstrap file for reading.\n"); + error= 1; + goto exit; + } + ret= fgets(query_str, 512, file); + if (ret == 0) + { + fprintf(stderr, "ERROR: Cannot read bootstrap file.\n"); + error= 1; + goto exit; + } + printf("# Query: %s\n", query_str); + +exit: + if (file) + { + fclose(file); + } + return error; +} + + +/** + Bootstrap the server + + Create a command line sequence to launch mysqld in bootstrap mode. This + will allow mysqld to launch a minimal server instance to read and + execute SQL commands from a file piped in (the boostrap file). We use + the --no-defaults option to skip reading values from the config file. + + The bootstrap mode skips loading of plugins and many other subsystems. + This allows the mysql_plugin tool to insert the correct rows into the + mysql.plugin table (for ENABLE) or delete the rows (for DISABLE). Once + the server is launched in normal mode, the plugin will be loaded + (for ENABLE) or not loaded (for DISABLE). In this way, we avoid the + (sometimes) complicated LOAD PLUGIN commands. + + @param[in] server_path Path to server executable + @param[in] bootstrap_file Name of bootstrap file to read + + @retval int error = 1, success = 0 +*/ + +static int bootstrap_server(char *server_path, char *bootstrap_file) +{ + char bootstrap_cmd[FN_REFLEN]; + int error= 0; + +#ifdef __WIN__ + char *format_str= 0; + const char *verbose_str= NULL; + + + if (opt_verbose) + verbose_str= "--console"; + else + verbose_str= ""; + if (has_spaces(opt_datadir) || has_spaces(opt_basedir) || + has_spaces(bootstrap_file)) + format_str= "\"%s %s --bootstrap --datadir=%s --basedir=%s < %s\""; + else + format_str= "%s %s --bootstrap --datadir=%s --basedir=%s < %s"; + + snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), format_str, + add_quotes(convert_path(server_path)), verbose_str, + add_quotes(opt_datadir), add_quotes(opt_basedir), + add_quotes(bootstrap_file)); +#else + snprintf(bootstrap_cmd, sizeof(bootstrap_cmd), + "%s --no-defaults --bootstrap --datadir=%s --basedir=%s" + " < %s", server_path, opt_datadir, opt_basedir, bootstrap_file); +#endif + + /* Execute the command */ + if (opt_verbose) + { + printf("# Command: %s\n", bootstrap_cmd); + } + error= run_command(bootstrap_cmd, "r"); + if (error) + fprintf(stderr, + "ERROR: Unexpected result from bootstrap. Error code: %d.\n", + error); + + return error; +} diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 014e4fe65cb..71bc936cfe6 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -1,5 +1,6 @@ /* Copyright (c) 2006, 2012, Oracle and/or its affiliates. + Copyright (C) 2010, 2012, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -38,15 +39,18 @@ static char mysql_path[FN_REFLEN]; static char mysqlcheck_path[FN_REFLEN]; -static my_bool opt_force, debug_info_flag, debug_check_flag, opt_silent; -static my_bool opt_not_used; /* For compatiblity */ -static uint my_end_arg= 0, opt_verbose; +static my_bool opt_force, opt_verbose, debug_info_flag, debug_check_flag, + opt_systables_only; +static my_bool opt_not_used, opt_silent; +static uint my_end_arg= 0; static char *opt_user= (char*)"root"; static DYNAMIC_STRING ds_args; static DYNAMIC_STRING conn_args; static char *opt_password= 0; +static char *opt_plugin_dir= 0, *opt_default_auth= 0; + static my_bool tty_password= 0; static char opt_tmpdir[FN_REFLEN] = ""; @@ -61,7 +65,7 @@ static my_bool not_used; /* Can't use GET_BOOL without a value pointer */ static my_bool opt_write_binlog; -#include <help_start.h> +#define OPT_SILENT OPT_MAX_CLIENT_OPTION static struct my_option my_long_options[]= { @@ -94,6 +98,10 @@ static struct my_option my_long_options[]= {"default-character-set", OPT_DEFAULT_CHARSET, "Not used by mysql_upgrade. Only for backward compatibility.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"default_auth", OPT_DEFAULT_AUTH, + "Default authentication client-side plugin to use.", + &opt_default_auth, &opt_default_auth, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"force", 'f', "Force execution of mysqlcheck even if mysql_upgrade " "has already been executed for the current version of MySQL.", &opt_force, &opt_force, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -107,6 +115,9 @@ static struct my_option my_long_options[]= {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", + &opt_plugin_dir, &opt_plugin_dir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection or 0 for default to, in " "order of preference, my.cnf, $MYSQL_TCP_PORT, " #if MYSQL_PORT_DEFAULT == 0 @@ -122,13 +133,17 @@ static struct my_option my_long_options[]= "Base name of shared memory.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"silent", 's', "Print less information", &opt_silent, + {"silent", OPT_SILENT, "Print less information", &opt_silent, &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"socket", 'S', "The socket file to use for connection.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #include <sslopt-longopts.h> {"tmpdir", 't', "Directory for temporary files.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"upgrade-system-tables", 's', "Only upgrade the system tables " + "do not try to upgrade the data.", + &opt_systables_only, &opt_systables_only, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"user", 'u', "User for login if not current user.", &opt_user, &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"verbose", 'v', "Display more output about the process.", @@ -141,8 +156,6 @@ static struct my_option my_long_options[]= {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; -#include <help_end.h> - static void free_used_memory(void) { @@ -215,6 +228,9 @@ static void add_one_option(DYNAMIC_STRING* ds, case GET_STR: arg= argument; break; + case GET_BOOL: + arg= (*(my_bool *)opt->value) ? "1" : "0"; + break; default: die("internal error at %s: %d",__FILE__, __LINE__); } @@ -236,9 +252,9 @@ get_one_option(int optid, const struct my_option *opt, printf("%s Ver %s Distrib %s, for %s (%s)\n", my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000")); - puts("MySQL utility for upgrading databases to new MySQL versions.\n"); + puts("MariaDB utility for upgrading databases to new MariaDB versions.\n"); my_print_help(my_long_options); - exit(0); + die(0); break; case '#': @@ -282,11 +298,13 @@ get_one_option(int optid, const struct my_option *opt, } add_option= 0; break; - case 's': + case OPT_SILENT: opt_verbose= 0; add_option= 0; break; case 'f': /* --force */ + case 's': /* --upgrade-system-tables */ + case OPT_WRITE_BINLOG: /* --write-binlog */ add_option= FALSE; break; @@ -296,6 +314,8 @@ get_one_option(int optid, const struct my_option *opt, case 'S': /* --socket */ case OPT_MYSQL_PROTOCOL: /* --protocol */ case OPT_SHARED_MEMORY_BASE_NAME: /* --shared-memory-base-name */ + case OPT_PLUGIN_DIR: /* --plugin-dir */ + case OPT_DEFAULT_AUTH: /* --default-auth */ add_one_option(&conn_args, opt, argument); break; } @@ -814,7 +834,7 @@ static int run_sql_fix_privilege_tables(void) } dynstr_free(&ds_result); - return found_real_errors; + DBUG_RETURN(found_real_errors); } @@ -833,9 +853,6 @@ int main(int argc, char **argv) char self_name[FN_REFLEN]; MY_INIT(argv[0]); -#ifdef __NETWARE__ - setscreenmode(SCR_AUTOCLOSE_ON_EXIT); -#endif #if __WIN__ if (GetModuleFileName(NULL, self_name, FN_REFLEN) == 0) @@ -848,7 +865,8 @@ int main(int argc, char **argv) init_dynamic_string(&conn_args, "", 512, 256)) die("Out of memory"); - load_defaults("my", load_default_groups, &argc, &argv); + if (load_defaults("my", load_default_groups, &argc, &argv)) + die(NULL); defaults_argv= argv; /* Must be freed by 'free_defaults' */ if (handle_options(&argc, &argv, my_long_options, get_one_option)) @@ -872,8 +890,15 @@ int main(int argc, char **argv) /* Find mysql */ find_tool(mysql_path, IF_WIN("mysql.exe", "mysql"), self_name); - /* Find mysqlcheck */ - find_tool(mysqlcheck_path, IF_WIN("mysqlcheck.exe", "mysqlcheck"), self_name); + if (!opt_systables_only) + { + /* Find mysqlcheck */ + find_tool(mysqlcheck_path, IF_WIN("mysqlcheck.exe", "mysqlcheck"), self_name); + } + else + { + printf("The --upgrade-system-tables option was used, databases won't be touched.\n"); + } /* Read the mysql_upgrade_info file to check if mysql_upgrade @@ -890,8 +915,8 @@ int main(int argc, char **argv) /* Run "mysqlcheck" and "mysql_fix_privilege_tables.sql" */ - if (run_mysqlcheck_fixnames() || - run_mysqlcheck_upgrade() || + if ((!opt_systables_only && + (run_mysqlcheck_fixnames() || run_mysqlcheck_upgrade())) || run_sql_fix_privilege_tables()) { /* diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index a7aa73fb02a..e2ebb883f77 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -1,5 +1,6 @@ /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. + Copyright (c) 2010, 2012, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,16 +13,13 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* maintaince of mysql databases */ #include "client_priv.h" #include <signal.h> -#ifdef THREAD #include <my_pthread.h> /* because of signal() */ -#endif #include <sys/stat.h> #include <mysql.h> #include <sql_common.h> @@ -33,7 +31,7 @@ #define MAX_TRUNC_LENGTH 3 char *host= NULL, *user= 0, *opt_password= 0, - *default_charset= NULL; + *default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME; char truncated_var_names[MAX_MYSQL_VAR][MAX_TRUNC_LENGTH]; char ex_var_names[MAX_MYSQL_VAR][FN_REFLEN]; ulonglong last_values[MAX_MYSQL_VAR]; @@ -46,6 +44,7 @@ static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations; static uint opt_count_iterations= 0, my_end_arg; static ulong opt_connect_timeout, opt_shutdown_timeout; static char * unix_port=0; +static char *opt_plugin_dir= 0, *opt_default_auth= 0; #ifdef HAVE_SMEM static char *shared_memory_base_name=0; @@ -125,10 +124,6 @@ static TYPELIB command_typelib= static struct my_option my_long_options[] = { -#ifdef __NETWARE__ - {"autoclose", OPT_AUTO_CLOSE, "Automatically close the screen on exit for Netware.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, -#endif {"count", 'c', "Number of iterations to make. This works with -i (--sleep) only.", &nr_iterations, &nr_iterations, 0, GET_UINT, @@ -144,7 +139,8 @@ static struct my_option my_long_options[] = &debug_info_flag, &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"force", 'f', - "Don't ask for confirmation on drop database; with multiple commands, continue even if an error occurs.", + "Don't ask for confirmation on drop database; with multiple commands, " + "continue even if an error occurs.", &option_force, &option_force, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"compress", 'C', "Use compression in server/client protocol.", @@ -175,8 +171,7 @@ static struct my_option my_long_options[] = "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - &tcp_port, - &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + &tcp_port, &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"protocol", OPT_MYSQL_PROTOCOL, "The protocol to use for connection (tcp, socket, pipe, memory).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"relative", 'r', @@ -184,10 +179,6 @@ static struct my_option my_long_options[] = "Currently only works with extended-status.", &opt_relative, &opt_relative, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"set-variable", 'O', - "Change the value of a variable. Please note that this option is " - "deprecated; you can set variables directly with --variable-name=value.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_SMEM {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME, "Base name of shared memory.", &shared_memory_base_name, &shared_memory_base_name, @@ -222,6 +213,13 @@ static struct my_option my_long_options[] = {"shutdown_timeout", OPT_SHUTDOWN_TIMEOUT, "", &opt_shutdown_timeout, &opt_shutdown_timeout, 0, GET_ULONG, REQUIRED_ARG, SHUTDOWN_DEF_TIMEOUT, 0, 3600*12, 0, 1, 0}, + {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", + &opt_plugin_dir, &opt_plugin_dir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"default_auth", OPT_DEFAULT_AUTH, + "Default authentication client-side plugin to use.", + &opt_default_auth, &opt_default_auth, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -236,11 +234,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int error = 0; switch(optid) { -#ifdef __NETWARE__ - case OPT_AUTO_CLOSE: - setscreenmode(SCR_AUTOCLOSE_ON_EXIT); - break; -#endif case 'c': opt_count_iterations= 1; break; @@ -250,7 +243,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), if (argument) { char *start=argument; - my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); + my_free(opt_password); opt_password=my_strdup(argument,MYF(MY_FAE)); while (*argument) *argument++= 'x'; /* Destroy argument */ if (*start) @@ -294,9 +287,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), charsets_dir = argument; #endif break; - case 'O': - WARN_DEPRECATED(VER_CELOSIA, "--set-variable", "--variable-name=value"); - break; case OPT_MYSQL_PROTOCOL: opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, opt->name); @@ -313,19 +303,18 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc,char *argv[]) { - int error= 0, ho_error; + int error= 0; MYSQL mysql; char **commands, **save_argv; MY_INIT(argv[0]); mysql_init(&mysql); - load_defaults("my",load_default_groups,&argc,&argv); + sf_leaking_memory=1; /* don't report memory leaks on early exits */ + if ((error= load_defaults("my",load_default_groups,&argc,&argv))) + goto err1; save_argv = argv; /* Save for free_defaults */ - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) - { - free_defaults(save_argv); - exit(ho_error); - } + if ((error=handle_options(&argc, &argv, my_long_options, get_one_option))) + goto err2; if (debug_info_flag) my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; if (debug_check_flag) @@ -340,8 +329,10 @@ int main(int argc,char *argv[]) if (tty_password) opt_password = get_tty_password(NullS); - VOID(signal(SIGINT,endprog)); /* Here if abort */ - VOID(signal(SIGTERM,endprog)); /* Here if abort */ + (void) signal(SIGINT,endprog); /* Here if abort */ + (void) signal(SIGTERM,endprog); /* Here if abort */ + + sf_leaking_memory=0; /* from now on we cleanup properly */ if (opt_compress) mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS); @@ -363,10 +354,15 @@ int main(int argc,char *argv[]) if (shared_memory_base_name) mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); #endif - if (default_charset) - mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); + mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); error_flags= (myf)(opt_nobeep ? 0 : ME_BELL); + if (opt_plugin_dir && *opt_plugin_dir) + mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir); + + if (opt_default_auth && *opt_default_auth) + mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + if (sql_connect(&mysql, option_wait)) { /* @@ -382,7 +378,8 @@ int main(int argc,char *argv[]) /* Return 0 if all commands are PING */ for (; argc > 0; argv++, argc--) { - if (find_type(argv[0], &command_typelib, 2) != ADMIN_PING) + if (find_type(argv[0], &command_typelib, FIND_TYPE_BASIC) != + ADMIN_PING) { error= 1; break; @@ -468,14 +465,17 @@ int main(int argc,char *argv[]) } /* got connection */ mysql_close(&mysql); - my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); - my_free(user,MYF(MY_ALLOW_ZERO_PTR)); +err2: + mysql_library_end(); + my_free(opt_password); + my_free(user); #ifdef HAVE_SMEM - my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); + my_free(shared_memory_base_name); #endif free_defaults(save_argv); +err1: my_end(my_end_arg); - exit(error ? 1 : 0); + exit(error); return 0; } @@ -606,7 +606,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) for (; argc > 0 ; argv++,argc--) { int command; - switch ((command= find_type(argv[0],&command_typelib,2))) { + switch ((command= find_type(argv[0],&command_typelib,FIND_TYPE_BASIC))) { case ADMIN_CREATE: { char buff[FN_REFLEN+20]; @@ -686,7 +686,6 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) REFRESH_MASTER | REFRESH_TABLE_STATS | REFRESH_INDEX_STATS | REFRESH_USER_STATS | - REFRESH_SLOW_QUERY_LOG | REFRESH_CLIENT_STATS))) { my_printf_error(0, "refresh failed; error: '%s'", error_flags, @@ -890,7 +889,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) } case ADMIN_FLUSH_SLOW_LOG: { - if (mysql_query(mysql,"flush slow query logs")) + if (mysql_query(mysql,"flush slow logs")) { my_printf_error(0, "flush failed; error: '%s'", error_flags, mysql_error(mysql)); @@ -997,23 +996,38 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) { char buff[128],crypted_pw[64]; time_t start_time; + char *typed_password= NULL, *verified= NULL; /* Do initialization the same way as we do in mysqld */ start_time=time((time_t*) 0); my_rnd_init(&rand_st,(ulong) start_time,(ulong) start_time/2); - if (argc < 2) + if (argc < 1) { my_printf_error(0, "Too few arguments to change password", error_flags); return 1; } - if (argv[1][0]) + else if (argc == 1) + { + /* prompt for password */ + typed_password= get_tty_password("New password: "); + verified= get_tty_password("Confirm new password: "); + if (strcmp(typed_password, verified) != 0) + { + my_printf_error(0,"Passwords don't match",MYF(ME_BELL)); + return -1; + } + } + else + typed_password= argv[1]; + + if (typed_password[0]) { - char *pw= argv[1]; - bool old= (find_type(argv[0], &command_typelib, 2) == + bool old= (find_type(argv[0], &command_typelib, FIND_TYPE_BASIC) == ADMIN_OLD_PASSWORD); #ifdef __WIN__ - uint pw_len= (uint) strlen(pw); - if (pw_len > 1 && pw[0] == '\'' && pw[pw_len-1] == '\'') + size_t pw_len= strlen(typed_password); + if (pw_len > 1 && typed_password[0] == '\'' && + typed_password[pw_len-1] == '\'') printf("Warning: single quotes were not trimmed from the password by" " your command\nline client, as you might have expected.\n"); #endif @@ -1051,9 +1065,9 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) } } if (old) - make_scrambled_password_323(crypted_pw, pw); + make_scrambled_password_323(crypted_pw, typed_password); else - make_scrambled_password(crypted_pw, pw); + make_scrambled_password(crypted_pw, typed_password); } else crypted_pw[0]=0; /* No password */ @@ -1088,6 +1102,12 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) return -1; } } + /* free up memory from prompted password */ + if (typed_password != argv[1]) + { + my_free(typed_password); + my_free(verified); + } argc--; argv++; break; } @@ -1145,13 +1165,11 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) return 0; } -#include <help_start.h> static void print_version(void) { printf("%s Ver %s Distrib %s, for %s on %s\n",my_progname,ADMIN_VERSION, MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); - NETWARE_SET_SCREEN_MODE(1); } @@ -1185,8 +1203,8 @@ static void usage(void) kill id,id,... Kill mysql threads"); #if MYSQL_VERSION_ID >= 32200 puts("\ - password new-password Change old password to new-password, MySQL 4.1 hashing.\n\ - old-password new-password Change old password to new-password in old format.\n"); + password [new-password] Change old password to new-password in current format\n\ + old-password [new-password] Change old password to new-password in old format"); #endif puts("\ ping Check if mysqld is alive\n\ @@ -1201,7 +1219,6 @@ static void usage(void) version Get version info from server"); } -#include <help_end.h> static int drop_db(MYSQL *mysql, const char *db) { diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index de44ef5d927..777e68902dd 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1,5 +1,6 @@ /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. + Copyright (c) 2009, 2012, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,23 +31,24 @@ #define MYSQL_CLIENT #undef MYSQL_SERVER +#define TABLE TABLE_CLIENT #include "client_priv.h" #include <my_time.h> /* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */ -#include "mysql_priv.h" +#include "sql_priv.h" #include "log_event.h" #include "sql_common.h" #include "my_dir.h" #include <welcome_copyright_notice.h> // ORACLE_WELCOME_COPYRIGHT_NOTICE -/* Needed for Rpl_filter */ -CHARSET_INFO* system_charset_info= &my_charset_utf8_general_ci; #include "sql_string.h" // needed for Rpl_filter #include "sql_list.h" // needed for Rpl_filter #include "rpl_filter.h" -Rpl_filter *binlog_filter; +#include "mysqld.h" + +Rpl_filter *binlog_filter= 0; #define BIN_LOG_HEADER_SIZE 4 #define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4) @@ -54,6 +56,8 @@ Rpl_filter *binlog_filter; #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES) +/* Needed for Rpl_filter */ +CHARSET_INFO* system_charset_info= &my_charset_utf8_general_ci; char server_version[SERVER_VERSION_LENGTH]; ulong server_id = 0; @@ -69,35 +73,37 @@ static FILE *result_file; #ifndef DBUG_OFF static const char* default_dbug_option = "d:t:o,/tmp/mysqlbinlog.trace"; #endif -static const char *load_default_groups[]= +static const char *load_groups[]= { "mysqlbinlog", "client", "client-server", "client-mariadb", 0 }; static void error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); static void warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2); static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0; -static bool opt_hexdump= 0; +static bool opt_hexdump= 0, opt_version= 0; const char *base64_output_mode_names[]= {"NEVER", "AUTO", "ALWAYS", "UNSPEC", "DECODE-ROWS", NullS}; TYPELIB base64_output_mode_typelib= { array_elements(base64_output_mode_names) - 1, "", base64_output_mode_names, NULL }; static enum_base64_output_mode opt_base64_output_mode= BASE64_OUTPUT_UNSPEC; -static const char *opt_base64_output_mode_str= NullS; -static const char* database= 0; +static char *opt_base64_output_mode_str= NullS; +static char* database= 0; static my_bool force_opt= 0, short_form= 0, remote_opt= 0; static my_bool debug_info_flag, debug_check_flag; static my_bool force_if_open_opt= 1; static my_bool opt_verify_binlog_checksum= 1; static ulonglong offset = 0; -static const char* host = 0; +static char* host = 0; static int port= 0; static uint my_end_arg; static const char* sock= 0; +static char *opt_plugindir= 0, *opt_default_auth= 0; + #ifdef HAVE_SMEM static char *shared_memory_base_name= 0; #endif -static const char* user = 0; +static char* user = 0; static char* pass = 0; static char *charset= 0; @@ -172,7 +178,7 @@ Log_event* read_remote_annotate_event(uchar* net_buf, ulong event_len, error_msg, glob_description_event, opt_verify_binlog_checksum))) { - my_free(event_buf, MYF(0)); + my_free(event_buf); return 0; } /* @@ -273,7 +279,7 @@ public: int init() { return init_dynamic_array(&file_names, sizeof(File_name_record), - 100,100 CALLER_INFO); + 100, 100); } void init_by_dir_name(const char *dir) @@ -295,7 +301,7 @@ public: { if (ptr->fname) { - my_free(ptr->fname, MYF(MY_WME)); + my_free(ptr->fname); delete ptr->event; bzero((char *)ptr, sizeof(File_name_record)); } @@ -518,12 +524,13 @@ Exit_status Load_log_processor::process_first_event(const char *bname, ptr= fname + target_dir_name_len; memcpy(ptr,bname,blen); ptr+= blen; - ptr+= my_sprintf(ptr, (ptr, "-%x", file_id)); + ptr+= sprintf(ptr, "-%x", file_id); if ((file= create_unique_file(fname,ptr)) < 0) { error("Could not construct local filename %s%s.", target_dir_name,bname); + my_free(fname); delete ce; DBUG_RETURN(ERROR_STOP); } @@ -531,9 +538,15 @@ Exit_status Load_log_processor::process_first_event(const char *bname, rec.fname= fname; rec.event= ce; + /* + fname is freed in process_event() + after Execute_load_query_log_event or Execute_load_log_event + will have been processed, otherwise in Load_log_processor::destroy() + */ if (set_dynamic(&file_names, (uchar*)&rec, file_id)) { error("Out of memory."); + my_free(fname); delete ce; DBUG_RETURN(ERROR_STOP); } @@ -742,6 +755,31 @@ print_use_stmt(PRINT_EVENT_INFO* pinfo, const Query_log_event *ev) /** + Print "SET skip_replication=..." statement when needed. + + Not all servers support this (only MariaDB from some version on). So we + mark the SET to only execute from the version of MariaDB that supports it, + and also only output it if we actually see events with the flag set, to not + get spurious errors on MySQL@Oracle servers of higher version that do not + support the flag. + + So we start out assuming @@skip_replication is 0, and only output a SET + statement when it changes. +*/ +static void +print_skip_replication_statement(PRINT_EVENT_INFO *pinfo, const Log_event *ev) +{ + int cur_val; + + cur_val= (ev->flags & LOG_EVENT_SKIP_REPLICATION_F) != 0; + if (cur_val == pinfo->skip_replication) + return; /* Not changed. */ + fprintf(result_file, "/*!50521 SET skip_replication=%d*/%s\n", + cur_val, pinfo->delimiter); + pinfo->skip_replication= cur_val; +} + +/** Prints the given event in base64 format. The header is printed to the head cache and the body is printed to @@ -885,7 +923,10 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, goto end; } else + { + print_skip_replication_statement(print_event_info, ev); ev->print(result_file, print_event_info); + } if (head->error == -1) goto err; break; @@ -918,6 +959,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, } else { + print_skip_replication_statement(print_event_info, ev); ce->print(result_file, print_event_info, TRUE); if (head->error == -1) goto err; @@ -970,7 +1012,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, */ convert_path_to_forward_slashes((char*) ce->fname); ce->print(result_file, print_event_info, TRUE); - my_free((char*)ce->fname,MYF(MY_WME)); + my_free((void*)ce->fname); delete ce; if (head->error == -1) goto err; @@ -989,10 +1031,16 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, if (head->error == -1) goto err; if (!remote_opt) + { ev->free_temp_buf(); // free memory allocated in dump_local_log_entries + } else - // disassociate but not free dump_remote_log_entries time memory + { + /* + disassociate but not free dump_remote_log_entries time memory + */ ev->temp_buf= 0; + } /* We don't want this event to be deleted now, so let's hide it (I (Guilhem) should later see if this triggers a non-serious Valgrind @@ -1028,11 +1076,12 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, if (fname) { convert_path_to_forward_slashes(fname); + print_skip_replication_statement(print_event_info, ev); exlq->print(result_file, print_event_info, fname); if (head->error == -1) { if (fname) - my_free(fname, MYF(MY_WME)); + my_free(fname); goto err; } } @@ -1042,7 +1091,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, } if (fname) - my_free(fname, MYF(MY_WME)); + my_free(fname); break; } case ANNOTATE_ROWS_EVENT: @@ -1163,6 +1212,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, /* FALL THROUGH */ } default: + print_skip_replication_statement(print_event_info, ev); ev->print(result_file, print_event_info); if (head->error == -1) goto err; @@ -1192,14 +1242,10 @@ end: } -static struct my_option my_long_options[] = +static struct my_option my_options[] = { {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef __NETWARE__ - {"autoclose", OPT_AUTO_CLOSE, "Automatically close the screen on exit for Netware.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, -#endif {"base64-output", OPT_BASE64_OUTPUT_MODE, /* 'unspec' is not mentioned because it is just a placeholder. */ "Determine when the output statements should be base64-encoded BINLOG " @@ -1207,10 +1253,11 @@ static struct my_option my_long_options[] = "row-based events; 'decode-rows' decodes row events into commented SQL " "statements if the --verbose option is also given; 'auto' prints base64 " "only when necessary (i.e., for row-based events and format description " - "events); 'always' prints base64 whenever possible. 'always' is for " - "debugging only and should not be used in a production system. If this " - "argument is not given, the default is 'auto'; if it is given with no " - "argument, 'always' is used.", + "events); 'always' prints base64 whenever possible. 'always' is " + "deprecated, will be removed in a future version, and should not be used " + "in a production system. --base64-output with no 'name' argument is " + "equivalent to --base64-output=always and is also deprecated. If no " + "--base64-output[=name] option is given at all, the default is 'auto'.", &opt_base64_output_mode_str, &opt_base64_output_mode_str, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, /* @@ -1235,6 +1282,10 @@ static struct my_option my_long_options[] = {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", &debug_info_flag, &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"default_auth", OPT_DEFAULT_AUTH, + "Default authentication client-side plugin to use.", + &opt_default_auth, &opt_default_auth, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"disable-log-bin", 'D', "Disable binary log. This is useful, if you " "enabled --to-last-log and are sending the output to the same MySQL server. " "This way you could avoid an endless loop. You would also like to use it " @@ -1260,6 +1311,9 @@ static struct my_option my_long_options[] = 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to connect to remote server.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", + &opt_plugindir, &opt_plugindir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection or 0 for default to, in " "order of preference, my.cnf, $MYSQL_TCP_PORT, " #if MYSQL_PORT_DEFAULT == 0 @@ -1268,11 +1322,6 @@ static struct my_option my_long_options[] = "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", &port, &port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"position", OPT_POSITION, "Deprecated. Use --start-position instead.", - &start_position, &start_position, 0, GET_ULL, - REQUIRED_ARG, BIN_LOG_HEADER_SIZE, BIN_LOG_HEADER_SIZE, - /* COM_BINLOG_DUMP accepts only 4 bytes for the position */ - (ulonglong)(~(uint32)0), 0, 0, 0}, {"protocol", OPT_MYSQL_PROTOCOL, "The protocol to use for connection (tcp, socket, pipe, memory).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -1281,7 +1330,7 @@ static struct my_option my_long_options[] = 0, 0}, {"result-file", 'r', "Direct output to a given file.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"server-id", OPT_SERVER_ID, + {"server-id", 0, "Extract only binlog entries created by the server having the given id.", &server_id, &server_id, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -1301,7 +1350,7 @@ static struct my_option my_long_options[] = &short_form, &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"socket", 'S', "The socket file to use for connection.", - &sock, &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, + &sock, &sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"start-datetime", OPT_START_DATETIME, "Start reading the binlog at first event having a datetime equal or " @@ -1433,23 +1482,22 @@ static void warning(const char *format,...) */ static void cleanup() { - my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); - my_free((char*) database, MYF(MY_ALLOW_ZERO_PTR)); - my_free((char*) host, MYF(MY_ALLOW_ZERO_PTR)); - my_free((char*) user, MYF(MY_ALLOW_ZERO_PTR)); - my_free((char*) dirname_for_local_load, MYF(MY_ALLOW_ZERO_PTR)); + my_free(pass); + my_free(database); + my_free(host); + my_free(user); + my_free(const_cast<char*>(dirname_for_local_load)); + delete binlog_filter; delete glob_description_event; if (mysql) mysql_close(mysql); } -#include <help_start.h> static void print_version() { printf("%s Ver 3.3 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE); - NETWARE_SET_SCREEN_MODE(1); } @@ -1461,8 +1509,8 @@ static void usage() Dumps a MySQL binary log in a format usable for viewing or for piping to\n\ the mysql command line client.\n\n"); printf("Usage: %s [options] log-files\n", my_progname); - my_print_help(my_long_options); - my_print_variables(my_long_options); + my_print_help(my_options); + my_print_variables(my_options); } @@ -1488,7 +1536,6 @@ static my_time_t convert_str_to_timestamp(const char* str) my_system_gmt_sec(&l_time, &dummy_my_timezone, &dummy_in_dst_time_gap); } -#include <help_end.h> extern "C" my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), @@ -1496,11 +1543,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), { bool tty_password=0; switch (optid) { -#ifdef __NETWARE__ - case OPT_AUTO_CLOSE: - setscreenmode(SCR_AUTOCLOSE_ON_EXIT); - break; -#endif #ifndef DBUG_OFF case '#': DBUG_PUSH(argument ? argument : default_dbug_option); @@ -1514,7 +1556,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), argument= (char*) ""; // Don't require password if (argument) { - my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); + my_free(pass); char *start=argument; pass= my_strdup(argument,MYF(MY_FAE)); while (*argument) *argument++= 'x'; /* Destroy argument */ @@ -1531,9 +1573,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'R': remote_opt= 1; break; - case OPT_POSITION: - WARN_DEPRECATED(VER_CELOSIA, "--position", "--start-position"); - break; case OPT_MYSQL_PROTOCOL: opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib, opt->name); @@ -1608,10 +1647,12 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'V': print_version(); - exit(0); + opt_version= 1; + break; case '?': usage(); - exit(0); + opt_version= 1; + break; } if (tty_password) pass= get_tty_password(NullS); @@ -1625,7 +1666,7 @@ static int parse_args(int *argc, char*** argv) int ho_error; result_file = stdout; - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) + if ((ho_error=handle_options(argc, argv, my_options, get_one_option))) exit(ho_error); if (debug_info_flag) my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; @@ -1656,6 +1697,12 @@ static Exit_status safe_connect() return ERROR_STOP; } + if (opt_plugindir && *opt_plugindir) + mysql_options(mysql, MYSQL_PLUGIN_DIR, opt_plugindir); + + if (opt_default_auth && *opt_default_auth) + mysql_options(mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + if (opt_protocol) mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol); #ifdef HAVE_SMEM @@ -2333,27 +2380,37 @@ int main(int argc, char** argv) my_init_time(); // for time functions init_alloc_root(&s_mem_root, 16384, 0); + if (load_defaults("my", load_groups, &argc, &argv)) + exit(1); + if (!(binlog_filter= new Rpl_filter)) { error("Failed to create Rpl_filter"); exit(1); } - if (load_defaults("my", load_default_groups, &argc, &argv)) - exit(1); - defaults_argv= argv; parse_args(&argc, (char***)&argv); - if (!argc) + if (!argc || opt_version) { - usage(); + if (!argc) + usage(); + cleanup(); free_defaults(defaults_argv); - exit(1); + my_end(my_end_arg); + exit(!opt_version); } if (opt_base64_output_mode == BASE64_OUTPUT_UNSPEC) opt_base64_output_mode= BASE64_OUTPUT_AUTO; + if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS) + warning("The --base64-output=always flag and the --base64-output flag " + "(with '=MODE' omitted), are deprecated. " + "The output generated when these flags are used cannot be " + "parsed by mysql 5.6.0 and later. " + "The flags will be removed in a future version. " + "Please use --base64-output=auto instead."); my_set_max_open_files(open_files_limit); @@ -2429,7 +2486,6 @@ int main(int argc, char** argv) my_fclose(result_file, MYF(0)); cleanup(); free_annotate_event(); - delete binlog_filter; free_root(&s_mem_root, MYF(0)); free_defaults(defaults_argv); my_free_open_file_info(); @@ -2453,12 +2509,13 @@ void *sql_alloc(size_t size) the server */ +#undef TABLE #include "my_decimal.h" #include "decimal.c" #include "my_decimal.cc" #include "log_event.cc" #include "log_event_old.cc" +#include "rpl_utility.cc" #include "sql_string.cc" #include "sql_list.cc" #include "rpl_filter.cc" -#include "rpl_utility.cc" diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index bfc18161380..4218f2da62c 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -1,5 +1,6 @@ /* Copyright (c) 2001, 2012, Oracle and/or its affiliates. + Copyright (c) 2010, 2011, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,6 +16,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +/* By Jani Tolonen, 2001-04-20, MySQL Development Team */ + #define CHECK_VERSION "2.7.0" #include "client_priv.h" @@ -42,14 +45,13 @@ static int my_end_arg; static char * opt_mysql_unix_port = 0; static char *opt_password = 0, *current_user = 0, *default_charset= 0, *current_host= 0; +static char *opt_plugin_dir= 0, *opt_default_auth= 0; static int first_error = 0; -DYNAMIC_ARRAY tables4repair; -#ifdef HAVE_SMEM +DYNAMIC_ARRAY tables4repair, tables4rebuild; static char *shared_memory_base_name=0; -#endif static uint opt_protocol=0; -enum operations { DO_CHECK, DO_REPAIR, DO_ANALYZE, DO_OPTIMIZE, DO_UPGRADE }; +enum operations { DO_CHECK=1, DO_REPAIR, DO_ANALYZE, DO_OPTIMIZE, DO_UPGRADE }; static struct my_option my_long_options[] = { @@ -63,10 +65,6 @@ static struct my_option my_long_options[] = "Instead of issuing one query for each table, use one query per database, naming all tables in the database in a comma-separated list.", &opt_all_in_1, &opt_all_in_1, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef __NETWARE__ - {"autoclose", OPT_AUTO_CLOSE, "Automatically 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, "If a checked table is corrupted, automatically fix it. Repairing will be done after all tables have been checked, if corrupted ones were found.", &opt_auto_repair, &opt_auto_repair, 0, GET_BOOL, NO_ARG, 0, @@ -105,6 +103,10 @@ static struct my_option my_long_options[] = {"default-character-set", OPT_DEFAULT_CHARSET, "Set the default character set.", &default_charset, &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"default_auth", OPT_DEFAULT_AUTH, + "Default authentication client-side plugin to use.", + &opt_default_auth, &opt_default_auth, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"fast",'F', "Check only tables that haven't been closed properly.", &opt_fast, &opt_fast, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -127,12 +129,13 @@ static struct my_option my_long_options[] = {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"host",'h', "Connect to host.", ¤t_host, - ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + ¤t_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"medium-check", 'm', "Faster than extended-check, but only finds 99.99 percent of all errors. Should be good enough for most cases.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"write-binlog", OPT_WRITE_BINLOG, - "Log ANALYZE, OPTIMIZE and REPAIR TABLE commands. Enabled by default; use --skip-write-binlog when commands should not be sent to replication slaves.", + "Log ANALYZE, OPTIMIZE and REPAIR TABLE commands. Use --skip-write-binlog " + "when commands should not be sent to replication slaves.", &opt_write_binlog, &opt_write_binlog, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"optimize", 'o', "Optimize table.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, @@ -144,14 +147,16 @@ static struct my_option my_long_options[] = {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", + &opt_plugin_dir, &opt_plugin_dir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection or 0 for default to, in " "order of preference, my.cnf, $MYSQL_TCP_PORT, " #if MYSQL_PORT_DEFAULT == 0 "/etc/services, " #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", - &opt_mysql_port, - &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, + &opt_mysql_port, &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"protocol", OPT_MYSQL_PROTOCOL, "The protocol to use for connection (tcp, socket, pipe, memory).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -213,18 +218,17 @@ static uint fixed_name_length(const char *name); static char *fix_table_name(char *dest, char *src); int what_to_do = 0; -#include <help_start.h> static void print_version(void) { printf("%s Ver %s Distrib %s, for %s (%s)\n", my_progname, CHECK_VERSION, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); - NETWARE_SET_SCREEN_MODE(1); } /* print_version */ static void usage(void) { + DBUG_ENTER("usage"); print_version(); puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000")); puts("This program can be used to CHECK (-c, -m, -C), REPAIR (-r), ANALYZE (-a),"); @@ -244,20 +248,18 @@ static void usage(void) print_defaults("my", load_default_groups); my_print_help(my_long_options); my_print_variables(my_long_options); + DBUG_VOID_RETURN; } /* usage */ -#include <help_end.h> static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) { + int orig_what_to_do= what_to_do; + DBUG_ENTER("get_one_option"); + switch(optid) { -#ifdef __NETWARE__ - case OPT_AUTO_CLOSE: - setscreenmode(SCR_AUTOCLOSE_ON_EXIT); - break; -#endif case 'a': what_to_do = DO_ANALYZE; break; @@ -292,7 +294,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), if (argument) { char *start = argument; - my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); + my_free(opt_password); opt_password = my_strdup(argument, MYF(MY_FAE)); while (*argument) *argument++= 'x'; /* Destroy argument */ if (*start) @@ -331,13 +333,21 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt->name); break; } - return 0; + + if (orig_what_to_do && (what_to_do != orig_what_to_do)) + { + fprintf(stderr, "Error: %s doesn't support multiple contradicting commands.\n", + my_progname); + DBUG_RETURN(1); + } + DBUG_RETURN(0); } static int get_options(int *argc, char ***argv) { int ho_error; + DBUG_ENTER("get_options"); if (*argc == 1) { @@ -345,8 +355,6 @@ static int get_options(int *argc, char ***argv) exit(0); } - load_defaults("my", load_default_groups, argc, argv); - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); @@ -370,29 +378,32 @@ static int get_options(int *argc, char ***argv) If there's no --default-character-set option given with --fix-table-name or --fix-db-name set the default character set to "utf8". */ - if (!default_charset && (opt_fix_db_names || opt_fix_table_names)) + if (!default_charset) { - default_charset= (char*) "utf8"; + if (opt_fix_db_names || opt_fix_table_names) + default_charset= (char*) "utf8"; + else + default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME; } - if (default_charset && !get_charset_by_csname(default_charset, MY_CS_PRIMARY, - MYF(MY_WME))) + if (strcmp(default_charset, MYSQL_AUTODETECT_CHARSET_NAME) && + !get_charset_by_csname(default_charset, MY_CS_PRIMARY, MYF(MY_WME))) { printf("Unsupported character set: %s\n", default_charset); - return 1; + DBUG_RETURN(1); } if (*argc > 0 && opt_alldbs) { printf("You should give only options, no arguments at all, with option\n"); printf("--all-databases. Please see %s --help for more information.\n", my_progname); - return 1; + DBUG_RETURN(1); } if (*argc < 1 && !opt_alldbs) { printf("You forgot to give the arguments! Please see %s --help\n", my_progname); printf("for more information.\n"); - return 1; + DBUG_RETURN(1); } if (tty_password) opt_password = get_tty_password(NullS); @@ -400,7 +411,7 @@ static int get_options(int *argc, char ***argv) my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO; if (debug_check_flag) my_end_arg= MY_CHECK_ERROR; - return(0); + DBUG_RETURN((0)); } /* get_options */ @@ -409,13 +420,14 @@ static int process_all_databases() MYSQL_ROW row; MYSQL_RES *tableres; int result = 0; + DBUG_ENTER("process_all_databases"); if (mysql_query(sock, "SHOW DATABASES") || !(tableres = mysql_store_result(sock))) { my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s", MYF(0), mysql_error(sock)); - return 1; + DBUG_RETURN(1); } if (verbose) printf("Processing databases\n"); @@ -424,7 +436,8 @@ static int process_all_databases() if (process_one_db(row[0])) result = 1; } - return result; + mysql_free_result(tableres); + DBUG_RETURN(result); } /* process_all_databases */ @@ -432,6 +445,8 @@ static int process_all_databases() static int process_databases(char **db_names) { int result = 0; + DBUG_ENTER("process_databases"); + if (verbose) printf("Processing databases\n"); for ( ; *db_names ; db_names++) @@ -439,14 +454,16 @@ static int process_databases(char **db_names) if (process_one_db(*db_names)) result = 1; } - return result; + DBUG_RETURN(result); } /* process_databases */ static int process_selected_tables(char *db, char **table_names, int tables) { + DBUG_ENTER("process_selected_tables"); + if (use_db(db)) - return 1; + DBUG_RETURN(1); if (opt_all_in_1 && what_to_do != DO_UPGRADE) { /* @@ -463,7 +480,7 @@ static int process_selected_tables(char *db, char **table_names, int tables) if (!(table_names_comma_sep = (char *) my_malloc((sizeof(char) * tot_length) + 4, MYF(MY_WME)))) - return 1; + DBUG_RETURN(1); for (end = table_names_comma_sep + 1; tables > 0; tables--, table_names++) @@ -473,12 +490,12 @@ static int process_selected_tables(char *db, char **table_names, int tables) } *--end = 0; handle_request_for_tables(table_names_comma_sep + 1, (uint) (tot_length - 1)); - my_free(table_names_comma_sep, MYF(0)); + my_free(table_names_comma_sep); } else for (; tables > 0; tables--, table_names++) handle_request_for_tables(*table_names, fixed_name_length(*table_names)); - return 0; + DBUG_RETURN(0); } /* process_selected_tables */ @@ -486,20 +503,24 @@ static uint fixed_name_length(const char *name) { const char *p; uint extra_length= 2; /* count the first/last backticks */ - + DBUG_ENTER("fixed_name_length"); + for (p= name; *p; p++) { if (*p == '`') extra_length++; else if (*p == '.') extra_length+= 2; + } - return (uint) ((p - name) + extra_length); + DBUG_RETURN((uint) ((p - name) + extra_length)); } static char *fix_table_name(char *dest, char *src) { + DBUG_ENTER("fix_table_name"); + *dest++= '`'; for (; *src; src++) { @@ -517,27 +538,28 @@ static char *fix_table_name(char *dest, char *src) } } *dest++= '`'; - return dest; + + DBUG_RETURN(dest); } static int process_all_tables_in_db(char *database) { - MYSQL_RES *res; + MYSQL_RES *UNINIT_VAR(res); MYSQL_ROW row; uint num_columns; my_bool system_database= 0; + DBUG_ENTER("process_all_tables_in_db"); - LINT_INIT(res); if (use_db(database)) - return 1; + DBUG_RETURN(1); if ((mysql_query(sock, "SHOW /*!50002 FULL*/ TABLES") && mysql_query(sock, "SHOW TABLES")) || !(res= mysql_store_result(sock))) { my_printf_error(0, "Error: Couldn't get table list for database %s: %s", MYF(0), database, mysql_error(sock)); - return 1; + DBUG_RETURN(1); } if (!strcmp(database, "mysql") || !strcmp(database, "MYSQL")) @@ -563,7 +585,7 @@ static int process_all_tables_in_db(char *database) if (!(tables=(char *) my_malloc(sizeof(char)*tot_length+4, MYF(MY_WME)))) { mysql_free_result(res); - return 1; + DBUG_RETURN(1); } for (end = tables + 1; (row = mysql_fetch_row(res)) ;) { @@ -576,7 +598,7 @@ static int process_all_tables_in_db(char *database) *--end = 0; if (tot_length) handle_request_for_tables(tables + 1, tot_length - 1); - my_free(tables, MYF(0)); + my_free(tables); } else { @@ -594,7 +616,7 @@ static int process_all_tables_in_db(char *database) } } mysql_free_result(res); - return 0; + DBUG_RETURN(0); } /* process_all_tables_in_db */ @@ -603,8 +625,10 @@ static int fix_table_storage_name(const char *name) { char qbuf[100 + NAME_LEN*4]; int rc= 0; + DBUG_ENTER("fix_table_storage_name"); + if (strncmp(name, "#mysql50#", 9)) - return 1; + DBUG_RETURN(1); sprintf(qbuf, "RENAME TABLE `%s` TO `%s`", name, name + 9); if (mysql_query(sock, qbuf)) { @@ -614,15 +638,17 @@ static int fix_table_storage_name(const char *name) } if (verbose) printf("%-50s %s\n", name, rc ? "FAILED" : "OK"); - return rc; + DBUG_RETURN(rc); } static int fix_database_storage_name(const char *name) { char qbuf[100 + NAME_LEN*4]; int rc= 0; + DBUG_ENTER("fix_database_storage_name"); + if (strncmp(name, "#mysql50#", 9)) - return 1; + DBUG_RETURN(1); sprintf(qbuf, "ALTER DATABASE `%s` UPGRADE DATA DIRECTORY NAME", name); if (mysql_query(sock, qbuf)) { @@ -632,11 +658,36 @@ static int fix_database_storage_name(const char *name) } if (verbose) printf("%-50s %s\n", name, rc ? "FAILED" : "OK"); - return rc; + DBUG_RETURN(rc); +} + +static int rebuild_table(char *name) +{ + char *query, *ptr; + int rc= 0; + DBUG_ENTER("rebuild_table"); + + query= (char*)my_malloc(sizeof(char) * (12 + fixed_name_length(name) + 6 + 1), + MYF(MY_WME)); + if (!query) + DBUG_RETURN(1); + ptr= strmov(query, "ALTER TABLE "); + ptr= fix_table_name(ptr, name); + ptr= strxmov(ptr, " FORCE", NullS); + if (mysql_real_query(sock, query, (uint)(ptr - query))) + { + fprintf(stderr, "Failed to %s\n", query); + fprintf(stderr, "Error: %s\n", mysql_error(sock)); + rc= 1; + } + my_free(query); + DBUG_RETURN(rc); } static int process_one_db(char *database) { + DBUG_ENTER("process_one_db"); + if (verbose) puts(database); if (what_to_do == DO_UPGRADE) @@ -648,35 +699,42 @@ static int process_one_db(char *database) database+= 9; } if (rc || !opt_fix_table_names) - return rc; + DBUG_RETURN(rc); } - return process_all_tables_in_db(database); + DBUG_RETURN(process_all_tables_in_db(database)); } static int use_db(char *database) { - if (mysql_get_server_version(sock) >= 50003 && - !my_strcasecmp(&my_charset_latin1, database, "information_schema")) - return 1; + DBUG_ENTER("use_db"); + + if (mysql_get_server_version(sock) >= FIRST_INFORMATION_SCHEMA_VERSION && + !my_strcasecmp(&my_charset_latin1, database, INFORMATION_SCHEMA_DB_NAME)) + DBUG_RETURN(1); + if (mysql_get_server_version(sock) >= FIRST_PERFORMANCE_SCHEMA_VERSION && + !my_strcasecmp(&my_charset_latin1, database, PERFORMANCE_SCHEMA_DB_NAME)) + DBUG_RETURN(1); if (mysql_select_db(sock, database)) { DBerror(sock, "when selecting the database"); - return 1; + DBUG_RETURN(1); } - return 0; + DBUG_RETURN(0); } /* use_db */ static int disable_binlog() { const char *stmt= "SET SQL_LOG_BIN=0"; + DBUG_ENTER("disable_binlog"); + if (mysql_query(sock, stmt)) { fprintf(stderr, "Failed to %s\n", stmt); fprintf(stderr, "Error: %s\n", mysql_error(sock)); - return 1; + DBUG_RETURN(1); } - return 0; + DBUG_RETURN(0); } static int handle_request_for_tables(char *tables, uint length) @@ -685,6 +743,7 @@ static int handle_request_for_tables(char *tables, uint length) char table_name_buff[NAME_CHAR_LEN*2*2+1], *table_name; uint query_length= 0; const char *op = 0; + DBUG_ENTER("handle_request_for_tables"); options[0] = 0; end = options; @@ -711,16 +770,15 @@ static int handle_request_for_tables(char *tables, uint length) op= (opt_write_binlog) ? "OPTIMIZE" : "OPTIMIZE NO_WRITE_TO_BINLOG"; break; case DO_UPGRADE: - return fix_table_storage_name(tables); + DBUG_RETURN(fix_table_storage_name(tables)); } if (!(query =(char *) my_malloc((sizeof(char)*(length+110)), MYF(MY_WME)))) - return 1; + DBUG_RETURN(1); if (opt_all_in_1) { /* No backticks here as we added them before */ - query_length= my_sprintf(query, - (query, "%s TABLE %s %s", op, tables, options)); + query_length= sprintf(query, "%s TABLE %s %s", op, tables, options); table_name= tables; } else @@ -739,23 +797,22 @@ static int handle_request_for_tables(char *tables, uint length) { sprintf(message, "when executing '%s TABLE ... %s'", op, options); DBerror(sock, message); - my_free(query, MYF(0)); - return 1; + my_free(query); + DBUG_RETURN(1); } print_result(); if (opt_flush_tables) { - query_length= my_sprintf(query, - (query, "FLUSH TABLES %s", table_name)); + query_length= sprintf(query, "FLUSH TABLES %s", table_name); if (mysql_real_query(sock, query, query_length)) { DBerror(sock, query); - my_free(query, MYF(0)); - return 1; + my_free(query); + DBUG_RETURN(1); } } - my_free(query, MYF(0)); - return 0; + my_free(query); + DBUG_RETURN(0); } @@ -765,7 +822,8 @@ static void print_result() MYSQL_ROW row; char prev[(NAME_LEN+9)*2+2]; uint i; - my_bool found_error=0; + my_bool found_error=0, table_rebuild=0; + DBUG_ENTER("print_result"); res = mysql_use_result(sock); @@ -784,8 +842,14 @@ static void print_result() */ if (found_error && opt_auto_repair && what_to_do != DO_REPAIR && strcmp(row[3],"OK")) - insert_dynamic(&tables4repair, (uchar*) prev); + { + if (table_rebuild) + insert_dynamic(&tables4rebuild, (uchar*) prev); + else + insert_dynamic(&tables4repair, (uchar*) prev); + } found_error=0; + table_rebuild=0; if (opt_silent) continue; } @@ -798,12 +862,16 @@ static void print_result() we have to run upgrade on it. In this case we write a nicer message than "Please do "REPAIR TABLE""... */ - if (!strcmp(row[2],"error") && strinstr(row[3],"REPAIR TABLE") != 0) + if (!strcmp(row[2],"error") && strstr(row[3],"REPAIR TABLE")) printf("%-50s %s", row[0], "Needs upgrade"); else printf("%s\n%-9s: %s", row[0], row[2], row[3]); if (strcmp(row[2],"note")) + { found_error=1; + if (opt_auto_repair && strstr(row[3], "ALTER TABLE") != NULL) + table_rebuild=1; + } } else printf("%-9s: %s", row[2], row[3]); @@ -812,8 +880,14 @@ static void print_result() } /* add the last table to be repaired to the list */ if (found_error && opt_auto_repair && what_to_do != DO_REPAIR) - insert_dynamic(&tables4repair, (uchar*) prev); + { + if (table_rebuild) + insert_dynamic(&tables4rebuild, (uchar*) prev); + else + insert_dynamic(&tables4repair, (uchar*) prev); + } mysql_free_result(res); + DBUG_VOID_RETURN; } @@ -834,28 +908,34 @@ static int dbConnect(char *host, char *user, char *passwd) #endif if (opt_protocol) mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); -#ifdef HAVE_SMEM if (shared_memory_base_name) mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); -#endif - if (default_charset) - mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset); + + if (opt_plugin_dir && *opt_plugin_dir) + mysql_options(&mysql_connection, MYSQL_PLUGIN_DIR, opt_plugin_dir); + + if (opt_default_auth && *opt_default_auth) + mysql_options(&mysql_connection, MYSQL_DEFAULT_AUTH, opt_default_auth); + + mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset); if (!(sock = mysql_real_connect(&mysql_connection, host, user, passwd, NULL, opt_mysql_port, opt_mysql_unix_port, 0))) { DBerror(&mysql_connection, "when trying to connect"); - return 1; + DBUG_RETURN(1); } mysql_connection.reconnect= 1; - return 0; + DBUG_RETURN(0); } /* dbConnect */ static void dbDisconnect(char *host) { + DBUG_ENTER("dbDisconnect"); if (verbose > 1) fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost"); mysql_close(sock); + DBUG_VOID_RETURN; } /* dbDisconnect */ @@ -871,45 +951,52 @@ static void DBerror(MYSQL *mysql, const char *when) static void safe_exit(int error) { + DBUG_ENTER("safe_exit"); if (!first_error) first_error= error; if (ignore_errors) - return; + DBUG_VOID_RETURN; if (sock) mysql_close(sock); + sf_leaking_memory= 1; /* don't check for memory leaks */ exit(error); + DBUG_VOID_RETURN; } int main(int argc, char **argv) { + int ret= EX_USAGE; + char **defaults_argv; + MY_INIT(argv[0]); + sf_leaking_memory=1; /* don't report memory leaks on early exits */ /* ** Check out the args */ + if (load_defaults("my", load_default_groups, &argc, &argv)) + goto end2; + + defaults_argv= argv; if (get_options(&argc, &argv)) - { - my_end(my_end_arg); - exit(EX_USAGE); - } + goto end1; + sf_leaking_memory=0; /* from now on we cleanup properly */ + + ret= EX_MYSQLERR; if (dbConnect(current_host, current_user, opt_password)) - exit(EX_MYSQLERR); + goto end1; + ret= 1; if (!opt_write_binlog) { if (disable_binlog()) - { - first_error= 1; goto end; - } } if (opt_auto_repair && - my_init_dynamic_array(&tables4repair, sizeof(char)*(NAME_LEN*2+2),16,64)) - { - first_error = 1; + (my_init_dynamic_array(&tables4repair, sizeof(char)*(NAME_LEN*2+2),16,64) || + my_init_dynamic_array(&tables4rebuild, sizeof(char)*(NAME_LEN*2+2),16,64))) goto end; - } if (opt_alldbs) process_all_databases(); @@ -923,7 +1010,7 @@ int main(int argc, char **argv) { uint i; - if (!opt_silent && tables4repair.elements) + if (!opt_silent && (tables4repair.elements || tables4rebuild.elements)) puts("\nRepairing tables"); what_to_do = DO_REPAIR; for (i = 0; i < tables4repair.elements ; i++) @@ -931,15 +1018,24 @@ int main(int argc, char **argv) char *name= (char*) dynamic_array_ptr(&tables4repair, i); handle_request_for_tables(name, fixed_name_length(name)); } + for (i = 0; i < tables4rebuild.elements ; i++) + rebuild_table((char*) dynamic_array_ptr(&tables4rebuild, i)); } + ret= test(first_error); + end: dbDisconnect(current_host); if (opt_auto_repair) + { delete_dynamic(&tables4repair); - my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); -#ifdef HAVE_SMEM - my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); -#endif + delete_dynamic(&tables4rebuild); + } + end1: + my_free(opt_password); + my_free(shared_memory_base_name); + mysql_library_end(); + free_defaults(defaults_argv); + end2: my_end(my_end_arg); - return(first_error!=0); + return ret; } /* main */ diff --git a/client/mysqldump.c b/client/mysqldump.c index b4db4400341..284ea1e760a 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1,5 +1,6 @@ /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. + Copyright (c) 2010, 2012, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* mysqldump.c - Dump a tables contents and format to an ASCII file @@ -52,7 +53,6 @@ #include "mysql.h" #include "mysql_version.h" #include "mysqld_error.h" -#include "../sql/ha_ndbcluster_tables.h" #include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */ @@ -117,6 +117,8 @@ static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0, opt_complete_insert= 0, opt_drop_database= 0, opt_replace_into= 0, opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1, + opt_slave_apply= 0, + opt_include_master_host_port= 0, opt_events= 0, opt_comments_used= 0, opt_alltspcs=0, opt_notspcs= 0; static my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0; @@ -137,7 +139,10 @@ static my_bool server_supports_switching_charsets= TRUE; static ulong opt_compatible_mode= 0; #define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1 #define MYSQL_OPT_MASTER_DATA_COMMENTED_SQL 2 +#define MYSQL_OPT_SLAVE_DATA_EFFECTIVE_SQL 1 +#define MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL 2 static uint opt_mysql_port= 0, opt_master_data; +static uint opt_slave_data; static uint my_end_arg; static char * opt_mysql_unix_port=0; static int first_error=0; @@ -150,6 +155,7 @@ FILE *stderror_file=0; static char *shared_memory_base_name=0; #endif static uint opt_protocol= 0; +static char *opt_plugin_dir= 0, *opt_default_auth= 0; /* Dynamic_string wrapper functions. In this file use these @@ -198,9 +204,6 @@ HASH ignore_table; static struct my_option my_long_options[] = { - {"all", OPT_ALL, "Deprecated. Use --create-options instead.", - &create_options, &create_options, 0, GET_BOOL, NO_ARG, 1, - 0, 0, 0, 0, 0}, {"all-databases", 'A', "Dump all the databases. This will be same as --databases with all databases selected.", &opt_alldbs, &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, @@ -225,10 +228,10 @@ static struct my_option my_long_options[] = {"allow-keywords", OPT_KEYWORDS, "Allow creation of column names that are keywords.", &opt_keywords, &opt_keywords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef __NETWARE__ - {"autoclose", OPT_AUTO_CLOSE, "Automatically close the screen on exit for Netware.", - 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, -#endif + {"apply-slave-statements", OPT_MYSQLDUMP_SLAVE_APPLY, + "Adds 'STOP SLAVE' prior to 'CHANGE MASTER' and 'START SLAVE' to bottom of dump.", + &opt_slave_apply, &opt_slave_apply, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, {"character-sets-dir", OPT_CHARSETS_DIR, "Directory for character set files.", (char**) &charsets_dir, (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -236,13 +239,20 @@ static struct my_option my_long_options[] = &opt_comments, &opt_comments, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"compatible", OPT_COMPATIBLE, - "Change the dump to be compatible with a given mode. By default tables are dumped in a format optimized for MySQL. Legal modes are: ansi, mysql323, mysql40, postgresql, oracle, mssql, db2, maxdb, no_key_options, no_table_options, no_field_options. One can use several modes separated by commas. Note: Requires MySQL server version 4.1.0 or higher. This option is ignored with earlier server versions.", + "Change the dump to be compatible with a given mode. By default tables " + "are dumped in a format optimized for MySQL. Legal modes are: ansi, " + "mysql323, mysql40, postgresql, oracle, mssql, db2, maxdb, no_key_options, " + "no_table_options, no_field_options. One can use several modes separated " + "by commas. Note: Requires MySQL server version 4.1.0 or higher. " + "This option is ignored with earlier server versions.", &opt_compatible_mode_str, &opt_compatible_mode_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"compact", OPT_COMPACT, - "Give less verbose output (useful for debugging). Disables structure comments and header/footer constructs. Enables options --skip-add-drop-table --skip-add-locks --skip-comments --skip-disable-keys --skip-set-charset.", - &opt_compact, &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, - 0, 0}, + "Give less verbose output (useful for debugging). Disables structure " + "comments and header/footer constructs. Enables options --skip-add-" + "drop-table --skip-add-locks --skip-comments --skip-disable-keys " + "--skip-set-charset.", + &opt_compact, &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"complete-insert", 'c', "Use complete insert statements.", &opt_complete_insert, &opt_complete_insert, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -281,8 +291,22 @@ static struct my_option my_long_options[] = &opt_delete_master_logs, &opt_delete_master_logs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"disable-keys", 'K', - "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER TABLE tb_name ENABLE KEYS */; will be put in the output.", &opt_disable_keys, + "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER " + "TABLE tb_name ENABLE KEYS */; will be put in the output.", &opt_disable_keys, &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"dump-slave", OPT_MYSQLDUMP_SLAVE_DATA, + "This causes the binary log position and filename of the master to be " + "appended to the dumped data output. Setting the value to 1, will print" + "it as a CHANGE MASTER command in the dumped data output; if equal" + " to 2, that command will be prefixed with a comment symbol. " + "This option will turn --lock-all-tables on, unless " + "--single-transaction is specified too (in which case a " + "global read lock is only taken a short time at the beginning of the dump " + "- don't forget to read about --single-transaction below). In all cases " + "any action on logs will happen at the exact moment of the dump." + "Option automatically turns --lock-tables off.", + &opt_slave_data, &opt_slave_data, 0, + GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL, 0, 0, 0}, {"events", 'E', "Dump events.", &opt_events, &opt_events, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -291,24 +315,18 @@ static struct my_option my_long_options[] = &extended_insert, &extended_insert, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"fields-terminated-by", OPT_FTB, - "Fields in the output file are terminated by the given string.", - &fields_terminated, &fields_terminated, 0, + "Fields in the output file are terminated by the given string.", + &fields_terminated, &fields_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"fields-enclosed-by", OPT_ENC, - "Fields in the output file are enclosed by the given character.", - &enclosed, &enclosed, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0}, + "Fields in the output file are enclosed by the given character.", + &enclosed, &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0}, {"fields-optionally-enclosed-by", OPT_O_ENC, - "Fields in the output file are optionally enclosed by the given character.", - &opt_enclosed, &opt_enclosed, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0}, - {"fields-escaped-by", OPT_ESC, + "Fields in the output file are optionally enclosed by the given character.", + &opt_enclosed, &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0}, + {"fields-escaped-by", OPT_ESC, "Fields in the output file are escaped by the given character.", - &escaped, &escaped, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"first-slave", OPT_FIRST_SLAVE, "Deprecated, renamed to --lock-all-tables.", - &opt_lock_all_tables, &opt_lock_all_tables, 0, GET_BOOL, NO_ARG, - 0, 0, 0, 0, 0, 0}, + &escaped, &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"flush-logs", 'F', "Flush logs file in server before starting dump. " "Note that if you dump many databases at once (using the option " "--databases= or --all-databases), the logs will be flushed for " @@ -342,10 +360,15 @@ static struct my_option my_long_options[] = "be specified with both database and table names, e.g., " "--ignore-table=database.table.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"include-master-host-port", OPT_MYSQLDUMP_INCLUDE_MASTER_HOST_PORT, + "Adds 'MASTER_HOST=<host>, MASTER_PORT=<port>' to 'CHANGE MASTER TO..' " + "in dump produced with --dump-slave.", &opt_include_master_host_port, + &opt_include_master_host_port, 0, GET_BOOL, NO_ARG, + 0, 0, 0, 0, 0, 0}, {"insert-ignore", OPT_INSERT_IGNORE, "Insert rows with INSERT IGNORE.", &opt_ignore, &opt_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"lines-terminated-by", OPT_LTB, + {"lines-terminated-by", OPT_LTB, "Lines in the output file are terminated by the given string.", &lines_terminated, &lines_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -396,7 +419,7 @@ static struct my_option my_long_options[] = NO_ARG, 0, 0, 0, 0, 0, 0}, {"no-data", 'd', "No row information.", &opt_no_data, &opt_no_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"no-set-names", 'N',"Suppress the SET NAMES statement", + {"no-set-names", 'N', "Same as --skip-set-charset.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"opt", OPT_OPTIMIZE, "Same as --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys. Enabled by default, disable with --skip-opt.", @@ -426,18 +449,17 @@ static struct my_option my_long_options[] = &opt_replace_into, &opt_replace_into, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"result-file", 'r', - "Direct output to a given file. This option should be used in MSDOS, because it prevents new line '\\n' from being converted to '\\r\\n' (carriage return + line feed).", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + "Direct output to a given file. This option should be used in systems " + "(e.g., DOS, Windows) that use carriage-return linefeed pairs (\\r\\n) " + "to separate text lines. This option ensures that only a single newline " + "is used.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"routines", 'R', "Dump stored routines (functions and procedures).", - &opt_routines, &opt_routines, 0, GET_BOOL, - NO_ARG, 0, 0, 0, 0, 0, 0}, + &opt_routines, &opt_routines, 0, GET_BOOL, + NO_ARG, 0, 0, 0, 0, 0, 0}, {"set-charset", OPT_SET_CHARSET, - "Add 'SET NAMES default_character_set' to the output. Enabled by default; suppress with --skip-set-charset.", + "Add 'SET NAMES default_character_set' to the output.", &opt_set_charset, &opt_set_charset, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, - {"set-variable", 'O', - "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_SMEM {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME, "Base name of shared memory.", &shared_memory_base_name, &shared_memory_base_name, @@ -496,6 +518,13 @@ static struct my_option my_long_options[] = &where, &where, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"xml", 'X', "Dump a database as well formed XML.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", + &opt_plugin_dir, &opt_plugin_dir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"default_auth", OPT_DEFAULT_AUTH, + "Default authentication client-side plugin to use.", + &opt_default_auth, &opt_default_auth, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -528,7 +557,6 @@ static int dump_tablespaces(char* ts_where); static void print_comment(FILE *sql_file, my_bool is_error, const char *format, ...); -#include <help_start.h> /* Print the supplied message if in verbose mode @@ -551,6 +579,8 @@ static void verbose_msg(const char *fmt, ...) vfprintf(stderr, fmt, args); va_end(args); + fflush(stderr); + DBUG_VOID_RETURN; } @@ -570,19 +600,17 @@ void check_io(FILE *file) static void print_version(void) { - printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION, + printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname_short,DUMP_VERSION, MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); - NETWARE_SET_SCREEN_MODE(1); } /* print_version */ static void short_usage_sub(void) { - printf("Usage: %s [OPTIONS] database [tables]\n", my_progname); + printf("Usage: %s [OPTIONS] database [tables]\n", my_progname_short); printf("OR %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n", - my_progname); - printf("OR %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname); - NETWARE_SET_SCREEN_MODE(1); + my_progname_short); + printf("OR %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname_short); } @@ -601,11 +629,9 @@ static void usage(void) static void short_usage(void) { short_usage_sub(); - printf("For more options, use %s --help\n", my_progname); + printf("For more options, use %s --help\n", my_progname_short); } -#include <help_end.h> - static void write_header(FILE *sql_file, char *db_name) { @@ -718,12 +744,6 @@ static void write_footer(FILE *sql_file) } /* write_footer */ -static void free_table_ent(char *key) -{ - my_free(key, MYF(0)); -} - - uchar* get_table_key(const char *entry, size_t *length, my_bool not_used __attribute__((unused))) { @@ -737,18 +757,13 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) { switch (optid) { -#ifdef __NETWARE__ - case OPT_AUTO_CLOSE: - setscreenmode(SCR_AUTOCLOSE_ON_EXIT); - break; -#endif case 'p': if (argument == disabled_my_option) argument= (char*) ""; /* Don't require password */ if (argument) { char *start=argument; - my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); + my_free(opt_password); opt_password=my_strdup(argument,MYF(MY_FAE)); while (*argument) *argument++= 'x'; /* Destroy argument */ if (*start) @@ -804,19 +819,14 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case '?': usage(); exit(0); - case 'O': - WARN_DEPRECATED(VER_CELOSIA, "--set-variable", "--variable-name=value"); - break; - case (int) OPT_ALL: - WARN_DEPRECATED(VER_CELOSIA, "--all", "--create-options"); - break; - case (int) OPT_FIRST_SLAVE: - WARN_DEPRECATED(VER_CELOSIA, "--first-slave", "--lock-all-tables"); - break; case (int) OPT_MASTER_DATA: if (!argument) /* work like in old versions */ opt_master_data= MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL; break; + case (int) OPT_MYSQLDUMP_SLAVE_DATA: + if (!argument) /* work like in old versions */ + opt_slave_data= MYSQL_OPT_SLAVE_DATA_EFFECTIVE_SQL; + break; case (int) OPT_OPTIMIZE: extended_insert= opt_drop= opt_lock= quick= create_options= opt_disable_keys= lock_tables= opt_set_charset= 1; @@ -912,12 +922,12 @@ static int get_options(int *argc, char ***argv) opt_net_buffer_length= *mysql_params->p_net_buffer_length; md_result_file= stdout; - load_defaults("my",load_default_groups,argc,argv); + if (load_defaults("my",load_default_groups,argc,argv)) + return 1; defaults_argv= *argv; - if (hash_init(&ignore_table, charset_info, 16, 0, 0, - (hash_get_key) get_table_key, - (hash_free_key) free_table_ent, 0)) + if (my_hash_init(&ignore_table, charset_info, 16, 0, 0, + (my_hash_get_key) get_table_key, my_free, 0)) return(EX_EOM); /* Don't copy internal log tables */ if (my_hash_insert(&ignore_table, @@ -946,33 +956,44 @@ static int get_options(int *argc, char ***argv) fields_terminated)) { fprintf(stderr, - "%s: You must use option --tab with --fields-...\n", my_progname); + "%s: You must use option --tab with --fields-...\n", my_progname_short); return(EX_USAGE); } + /* We don't delete master logs if slave data option */ + if (opt_slave_data) + { + opt_lock_all_tables= !opt_single_transaction; + opt_master_data= 0; + opt_delete_master_logs= 0; + } + /* Ensure consistency of the set of binlog & locking options */ if (opt_delete_master_logs && !opt_master_data) opt_master_data= MYSQL_OPT_MASTER_DATA_COMMENTED_SQL; if (opt_single_transaction && opt_lock_all_tables) { fprintf(stderr, "%s: You can't use --single-transaction and " - "--lock-all-tables at the same time.\n", my_progname); + "--lock-all-tables at the same time.\n", my_progname_short); return(EX_USAGE); } if (opt_master_data) + { opt_lock_all_tables= !opt_single_transaction; + opt_slave_data= 0; + } if (opt_single_transaction || opt_lock_all_tables) lock_tables= 0; if (enclosed && opt_enclosed) { - fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname); + fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname_short); return(EX_USAGE); } if ((opt_databases || opt_alldbs) && path) { fprintf(stderr, "%s: --databases or --all-databases can't be used with --tab.\n", - my_progname); + my_progname_short); return(EX_USAGE); } if (strcmp(default_charset, charset_info->csname) && @@ -1024,7 +1045,7 @@ static void die(int error_num, const char* fmt_reason, ...) my_vsnprintf(buffer, sizeof(buffer), fmt_reason, args); va_end(args); - fprintf(stderr, "%s: %s\n", my_progname, buffer); + fprintf(stderr, "%s: %s\n", my_progname_short, buffer); fflush(stderr); ignore_errors= 0; /* force the exit */ @@ -1058,7 +1079,7 @@ static void maybe_die(int error_num, const char* fmt_reason, ...) my_vsnprintf(buffer, sizeof(buffer), fmt_reason, args); va_end(args); - fprintf(stderr, "%s: %s\n", my_progname, buffer); + fprintf(stderr, "%s: %s\n", my_progname_short, buffer); fflush(stderr); maybe_exit(error_num); @@ -1371,120 +1392,68 @@ static int switch_character_set_results(MYSQL *mysql, const char *cs_name) } /** - Rewrite CREATE TRIGGER statement, enclosing DEFINER clause in - version-specific comment. - - This function parses the CREATE TRIGGER statement and encloses - DEFINER-clause in version-specific comment: - input query: CREATE DEFINER=a@b TRIGGER ... - rewritten query: CREATE * / / *!50017 DEFINER=a@b * / / *!50003 TRIGGER ... - - @note This function will go away when WL#3995 is implemented. - - @param[in] trigger_def_str CREATE TRIGGER statement string. - @param[in] trigger_def_length length of the trigger_def_str. - - @return pointer to the new allocated query string. -*/ - -static char *cover_definer_clause_in_trigger(const char *trigger_def_str, - uint trigger_def_length) -{ - char *query_str= NULL; - char *definer_begin= my_case_str(trigger_def_str, trigger_def_length, - C_STRING_WITH_LEN(" DEFINER")); - char *definer_end; - - if (!definer_begin) - return NULL; - - definer_end= my_case_str(definer_begin, strlen(definer_begin), - C_STRING_WITH_LEN(" TRIGGER")); - - if (definer_end) - { - char *query_str_tail; - - /* - Allocate memory for new query string: original string - from SHOW statement and version-specific comments. - */ - query_str= alloc_query_str(trigger_def_length + 23); - - query_str_tail= strnmov(query_str, - trigger_def_str, - definer_begin - trigger_def_str); - - query_str_tail= strmov(query_str_tail, - "*/ /*!50017"); - - query_str_tail= strnmov(query_str_tail, - definer_begin, - definer_end - definer_begin); - - query_str_tail= strxmov(query_str_tail, - "*/ /*!50003", - definer_end, - NullS); - } - - return query_str; -} - -/** - Rewrite CREATE FUNCTION or CREATE PROCEDURE statement, enclosing DEFINER - clause in version-specific comment. + Rewrite statement, enclosing DEFINER clause in version-specific comment. - This function parses the CREATE FUNCTION | PROCEDURE statement and - encloses DEFINER-clause in version-specific comment: + This function parses any CREATE statement and encloses DEFINER-clause in + version-specific comment: input query: CREATE DEFINER=a@b FUNCTION ... rewritten query: CREATE * / / *!50020 DEFINER=a@b * / / *!50003 FUNCTION ... @note This function will go away when WL#3995 is implemented. - @param[in] def_str CREATE FUNCTION|PROCEDURE statement string. - @param[in] def_str_length length of the def_str. + @param[in] stmt_str CREATE statement string. + @param[in] stmt_length Length of the stmt_str. + @param[in] definer_version_str Minimal MySQL version number when + DEFINER clause is supported in the + given statement. + @param[in] definer_version_length Length of definer_version_str. + @param[in] stmt_version_str Minimal MySQL version number when the + given statement is supported. + @param[in] stmt_version_length Length of stmt_version_str. + @param[in] keyword_str Keyword to look for after CREATE. + @param[in] keyword_length Length of keyword_str. @return pointer to the new allocated query string. */ -static char *cover_definer_clause_in_sp(const char *def_str, - uint def_str_length) +static char *cover_definer_clause(const char *stmt_str, + uint stmt_length, + const char *definer_version_str, + uint definer_version_length, + const char *stmt_version_str, + uint stmt_version_length, + const char *keyword_str, + uint keyword_length) { - char *query_str= NULL; - char *definer_begin= my_case_str(def_str, def_str_length, + char *definer_begin= my_case_str(stmt_str, stmt_length, C_STRING_WITH_LEN(" DEFINER")); - char *definer_end; + char *definer_end= NULL; + + char *query_str= NULL; + char *query_ptr; if (!definer_begin) return NULL; definer_end= my_case_str(definer_begin, strlen(definer_begin), - C_STRING_WITH_LEN(" PROCEDURE")); + keyword_str, keyword_length); if (!definer_end) - { - definer_end= my_case_str(definer_begin, strlen(definer_begin), - C_STRING_WITH_LEN(" FUNCTION")); - } + return NULL; - if (definer_end) - { - char *query_str_tail; + /* + Allocate memory for new query string: original string + from SHOW statement and version-specific comments. + */ + query_str= alloc_query_str(stmt_length + 23); - /* - Allocate memory for new query string: original string - from SHOW statement and version-specific comments. - */ - query_str= alloc_query_str(def_str_length + 23); - - query_str_tail= strnmov(query_str, def_str, definer_begin - def_str); - query_str_tail= strmov(query_str_tail, "*/ /*!50020"); - query_str_tail= strnmov(query_str_tail, definer_begin, - definer_end - definer_begin); - query_str_tail= strxmov(query_str_tail, "*/ /*!50003", - definer_end, NullS); - } + query_ptr= strnmov(query_str, stmt_str, definer_begin - stmt_str); + query_ptr= strnmov(query_ptr, C_STRING_WITH_LEN("*/ /*!")); + query_ptr= strnmov(query_ptr, definer_version_str, definer_version_length); + query_ptr= strnmov(query_ptr, definer_begin, definer_end - definer_begin); + query_ptr= strnmov(query_ptr, C_STRING_WITH_LEN("*/ /*!")); + query_ptr= strnmov(query_ptr, stmt_version_str, stmt_version_length); + query_ptr= strxmov(query_ptr, definer_end, NullS); return query_str; } @@ -1516,16 +1485,17 @@ static void free_resources() { if (md_result_file && md_result_file != stdout) my_fclose(md_result_file, MYF(0)); - my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); - my_free(current_host, MYF(MY_ALLOW_ZERO_PTR)); - if (hash_inited(&ignore_table)) - hash_free(&ignore_table); + my_free(opt_password); + my_free(current_host); + if (my_hash_inited(&ignore_table)) + my_hash_free(&ignore_table); if (extended_insert) dynstr_free(&extended_row); if (insert_pat_inited) dynstr_free(&insert_pat); if (defaults_argv) free_defaults(defaults_argv); + mysql_library_end(); my_end(my_end_arg); } @@ -1570,9 +1540,16 @@ static int connect_to_db(char *host, char *user,char *passwd) mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); #endif mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset); - if (!(mysql= mysql_real_connect(&mysql_connection,host,user,passwd, - NULL,opt_mysql_port,opt_mysql_unix_port, - 0))) + + if (opt_plugin_dir && *opt_plugin_dir) + mysql_options(&mysql_connection, MYSQL_PLUGIN_DIR, opt_plugin_dir); + + if (opt_default_auth && *opt_default_auth) + mysql_options(&mysql_connection, MYSQL_DEFAULT_AUTH, opt_default_auth); + + mysql= &mysql_connection; /* So we can mysql_close() it properly */ + if (!mysql_real_connect(&mysql_connection,host,user,passwd, + NULL,opt_mysql_port,opt_mysql_unix_port, 0)) { DB_error(&mysql_connection, "when trying to connect"); DBUG_RETURN(1); @@ -1631,7 +1608,7 @@ static void unescape(FILE *file,char *pos,uint length) fputs(tmp, file); fputc('\'', file); check_io(file); - my_free(tmp, MYF(MY_WME)); + my_free(tmp); DBUG_VOID_RETURN; } /* unescape */ @@ -2175,6 +2152,8 @@ static uint dump_events_for_db(char *db) */ if (strlen(row[3]) != 0) { + char *query_str; + if (opt_drop) fprintf(sql_file, "/*!50106 DROP EVENT IF EXISTS %s */%s\n", event_name, delimiter); @@ -2182,7 +2161,7 @@ static uint dump_events_for_db(char *db) if (create_delimiter(row[3], delimiter, sizeof(delimiter)) == NULL) { fprintf(stderr, "%s: Warning: Can't create delimiter for event '%s'\n", - my_progname, event_name); + my_progname_short, event_name); DBUG_RETURN(1); } @@ -2201,31 +2180,36 @@ static uint dump_events_for_db(char *db) row[4], /* character_set_results */ row[5]); /* collation_connection */ } - else - { - /* - mysqldump is being run against the server, that does not - provide character set information in SHOW CREATE - statements. + else + { + /* + mysqldump is being run against the server, that does not + provide character set information in SHOW CREATE + statements. - NOTE: the dump may be incorrect, since character set - information is required in order to restore event properly. - */ + NOTE: the dump may be incorrect, since character set + information is required in order to restore event properly. + */ - fprintf(sql_file, - "--\n" - "-- WARNING: old server version. " - "The following dump may be incomplete.\n" - "--\n"); - } + fprintf(sql_file, + "--\n" + "-- WARNING: old server version. " + "The following dump may be incomplete.\n" + "--\n"); + } switch_sql_mode(sql_file, delimiter, row[1]); switch_time_zone(sql_file, delimiter, row[2]); + query_str= cover_definer_clause(row[3], strlen(row[3]), + C_STRING_WITH_LEN("50117"), + C_STRING_WITH_LEN("50106"), + C_STRING_WITH_LEN(" EVENT")); + fprintf(sql_file, "/*!50106 %s */ %s\n", - (const char *) row[3], + (const char *) (query_str != NULL ? query_str : row[3]), (const char *) delimiter); restore_time_zone(sql_file, delimiter); @@ -2264,7 +2248,7 @@ static uint dump_events_for_db(char *db) mysql_free_result(event_list_res); if (lock_tables) - VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES")); + (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"); DBUG_RETURN(0); } @@ -2404,7 +2388,16 @@ static uint dump_routines_for_db(char *db) fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;\n", routine_type[i], routine_name); - query_str= cover_definer_clause_in_sp(row[2], strlen(row[2])); + query_str= cover_definer_clause(row[2], strlen(row[2]), + C_STRING_WITH_LEN("50020"), + C_STRING_WITH_LEN("50003"), + C_STRING_WITH_LEN(" FUNCTION")); + + if (!query_str) + query_str= cover_definer_clause(row[2], strlen(row[2]), + C_STRING_WITH_LEN("50020"), + C_STRING_WITH_LEN("50003"), + C_STRING_WITH_LEN(" PROCEDURE")); if (mysql_num_fields(routine_res) >= 6) { @@ -2460,7 +2453,7 @@ static uint dump_routines_for_db(char *db) } } - my_free(query_str, MYF(MY_ALLOW_ZERO_PTR)); + my_free(query_str); } } /* end of routine printing */ mysql_free_result(routine_res); @@ -2480,7 +2473,7 @@ static uint dump_routines_for_db(char *db) DBUG_RETURN(1); if (lock_tables) - VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES")); + (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"); DBUG_RETURN(0); } @@ -2617,6 +2610,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, if (strcmp(field->name, "View") == 0) { char *scv_buff= NULL; + my_ulonglong n_cols; verbose_msg("-- It's a view, create dummy table for view\n"); @@ -2631,8 +2625,8 @@ static uint get_table_structure(char *table, char *db, char *table_type, the same name in order to satisfy views that depend on this view. The table will be removed when the actual view is created. - The properties of each column, aside from the data type, are not - preserved in this temporary table, because they are not necessary. + The properties of each column, are not preserved in this temporary + table, because they are not necessary. This will not be necessary once we can determine dependencies between views and can simply dump them in the appropriate order. @@ -2652,15 +2646,30 @@ static uint get_table_structure(char *table, char *db, char *table_type, if (mysql_errno(mysql) == ER_VIEW_INVALID) fprintf(sql_file, "\n-- failed on view %s: %s\n\n", result_table, scv_buff ? scv_buff : ""); - my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR)); + my_free(scv_buff); DBUG_RETURN(0); } else - my_free(scv_buff, MYF(MY_ALLOW_ZERO_PTR)); + my_free(scv_buff); - if (mysql_num_rows(result)) + n_cols= mysql_num_rows(result); + if (0 != n_cols) { + + /* + The actual formula is based on the column names and how the .FRM + files are stored and is too volatile to be repeated here. + Thus we simply warn the user if the columns exceed a limit we + know works most of the time. + */ + if (n_cols >= 1000) + fprintf(stderr, + "-- Warning: Creating a stand-in table for view %s may" + " fail when replaying the dump file produced because " + "of the number of columns exceeding 1000. Exercise " + "caution when replaying the produced dump file.\n", + table); if (opt_drop) { /* @@ -2687,14 +2696,19 @@ static uint get_table_structure(char *table, char *db, char *table_type, row= mysql_fetch_row(result); - fprintf(sql_file, " %s %s", quote_name(row[0], name_buff, 0), - row[1]); + /* + The actual column type doesn't matter anyway, since the table will + be dropped at run time. + We do tinyint to avoid hitting the row size limit. + */ + fprintf(sql_file, " %s tinyint NOT NULL", + quote_name(row[0], name_buff, 0)); while((row= mysql_fetch_row(result))) { /* col name, col type */ - fprintf(sql_file, ",\n %s %s", - quote_name(row[0], name_buff, 0), row[1]); + fprintf(sql_file, ",\n %s tinyint NOT NULL", + quote_name(row[0], name_buff, 0)); } /* @@ -2799,7 +2813,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, else { verbose_msg("%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n", - my_progname, mysql_error(mysql)); + my_progname_short, mysql_error(mysql)); my_snprintf(query_buff, sizeof(query_buff), show_fields_stmt, db, table); @@ -2910,7 +2924,7 @@ static uint get_table_structure(char *table, char *db, char *table_type, goto continue_xml; } fprintf(stderr, "%s: Can't get keys for table %s (%s)\n", - my_progname, result_table, mysql_error(mysql)); + my_progname_short, result_table, mysql_error(mysql)); if (path) my_fclose(sql_file, MYF(MY_WME)); DBUG_RETURN(0); @@ -3135,9 +3149,10 @@ static int dump_trigger(FILE *sql_file, MYSQL_RES *show_create_trigger_rs, continue; } - query_str= cover_definer_clause_in_trigger(row[2], strlen(row[2])); - - + query_str= cover_definer_clause(row[2], strlen(row[2]), + C_STRING_WITH_LEN("50017"), + C_STRING_WITH_LEN("50003"), + C_STRING_WITH_LEN(" TRIGGER")); if (switch_db_collation(sql_file, db_name, ";", db_cl_name, row[5], &db_cl_altered)) DBUG_RETURN(TRUE); @@ -3164,7 +3179,7 @@ static int dump_trigger(FILE *sql_file, MYSQL_RES *show_create_trigger_rs, DBUG_RETURN(TRUE); } - my_free(query_str, MYF(MY_ALLOW_ZERO_PTR)); + my_free(query_str); } DBUG_RETURN(FALSE); @@ -3565,7 +3580,7 @@ static void dump_table(char *table, char *db) if (mysql_num_fields(res) != num_fields) { fprintf(stderr,"%s: Error in field count for table: %s ! Aborting.\n", - my_progname, result_table); + my_progname_short, result_table); error= EX_CONSCHECK; goto err; } @@ -3649,7 +3664,7 @@ static void dump_table(char *table, char *db) { if (length) { - if (!IS_NUM_FIELD(field)) + if (!(field->flags & NUM_FLAG)) { /* "length * 2 + 2" is OK for both HEX and non-HEX modes: @@ -3717,7 +3732,7 @@ static void dump_table(char *table, char *db) } if (row[i]) { - if (!IS_NUM_FIELD(field)) + if (!(field->flags & NUM_FLAG)) { if (opt_xml) { @@ -3830,7 +3845,7 @@ static void dump_table(char *table, char *db) { my_snprintf(buf, sizeof(buf), "%s: Error %d: %s when dumping table %s at row: %ld\n", - my_progname, + my_progname_short, mysql_errno(mysql), mysql_error(mysql), result_table, @@ -4024,8 +4039,8 @@ static int dump_tablespaces(char* ts_where) DBUG_RETURN(0); } - my_printf_error(0, "Error: '%s' when trying to dump tablespaces", - MYF(0), mysql_error(mysql)); + fprintf(stderr, "%s: Error: '%s' when trying to dump tablespaces\n", + my_progname_short, mysql_error(mysql)); DBUG_RETURN(1); } @@ -4154,31 +4169,41 @@ static int dump_all_databases() return 1; while ((row= mysql_fetch_row(tableres))) { - if (mysql_get_server_version(mysql) >= 50003 && - !my_strcasecmp(&my_charset_latin1, row[0], "information_schema")) + if (mysql_get_server_version(mysql) >= FIRST_INFORMATION_SCHEMA_VERSION && + !my_strcasecmp(&my_charset_latin1, row[0], INFORMATION_SCHEMA_DB_NAME)) + continue; + + if (mysql_get_server_version(mysql) >= FIRST_PERFORMANCE_SCHEMA_VERSION && + !my_strcasecmp(&my_charset_latin1, row[0], PERFORMANCE_SCHEMA_DB_NAME)) continue; if (dump_all_tables_in_db(row[0])) result=1; } + mysql_free_result(tableres); if (seen_views) { if (mysql_query(mysql, "SHOW DATABASES") || !(tableres= mysql_store_result(mysql))) { - my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s", - MYF(0), mysql_error(mysql)); + fprintf(stderr, "%s: Error: Couldn't execute 'SHOW DATABASES': %s\n", + my_progname_short, mysql_error(mysql)); return 1; } while ((row= mysql_fetch_row(tableres))) { - if (mysql_get_server_version(mysql) >= 50003 && - !my_strcasecmp(&my_charset_latin1, row[0], "information_schema")) + if (mysql_get_server_version(mysql) >= FIRST_INFORMATION_SCHEMA_VERSION && + !my_strcasecmp(&my_charset_latin1, row[0], INFORMATION_SCHEMA_DB_NAME)) + continue; + + if (mysql_get_server_version(mysql) >= FIRST_PERFORMANCE_SCHEMA_VERSION && + !my_strcasecmp(&my_charset_latin1, row[0], PERFORMANCE_SCHEMA_DB_NAME)) continue; if (dump_all_views_in_db(row[0])) result=1; } + mysql_free_result(tableres); } return result; } @@ -4307,8 +4332,6 @@ static int init_dumping(char *database, int init_func(char*)) check_io(md_result_file); } } - if (extended_insert) - init_dynamic_string_checked(&extended_row, "", 1024, 1024); return 0; } /* init_dumping */ @@ -4317,7 +4340,7 @@ static int init_dumping(char *database, int init_func(char*)) my_bool include_table(const uchar *hash_key, size_t len) { - return !hash_search(&ignore_table, hash_key, len); + return ! my_hash_search(&ignore_table, hash_key, len); } @@ -4379,6 +4402,8 @@ static int dump_all_tables_in_db(char *database) if (mysql_refresh(mysql, REFRESH_LOG)) DB_error(mysql, "when doing refresh"); /* We shall continue here, if --force was given */ + else + verbose_msg("-- dump_all_tables_in_db : logs flushed successfully!\n"); } while ((table= getTableName(0))) { @@ -4386,7 +4411,7 @@ static int dump_all_tables_in_db(char *database) if (include_table((uchar*) hash_key, end - hash_key)) { dump_table(table,database); - my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); + my_free(order_by); order_by= 0; if (opt_dump_triggers && mysql_get_server_version(mysql) >= 50009) { @@ -4415,7 +4440,7 @@ static int dump_all_tables_in_db(char *database) check_io(md_result_file); } if (lock_tables) - VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES")); + (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"); if (flush_privileges && using_mysql_db == 0) { fprintf(md_result_file,"\n--\n-- Flush Grant Tables \n--\n"); @@ -4476,6 +4501,8 @@ static my_bool dump_all_views_in_db(char *database) if (mysql_refresh(mysql, REFRESH_LOG)) DB_error(mysql, "when doing refresh"); /* We shall continue here, if --force was given */ + else + verbose_msg("-- dump_all_views_in_db : logs flushed successfully!\n"); } while ((table= getTableName(0))) { @@ -4489,7 +4516,7 @@ static my_bool dump_all_views_in_db(char *database) check_io(md_result_file); } if (lock_tables) - VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES")); + (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"); return 0; } /* dump_all_tables_in_db */ @@ -4538,7 +4565,7 @@ static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root) } mysql_free_result(table_res); } - DBUG_PRINT("exit", ("new_table_name: %s", val_or_null(name))); + DBUG_PRINT("exit", ("new_table_name: %s", name)); DBUG_RETURN(name); } @@ -4585,10 +4612,12 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } end= pos; - /* Can't LOCK TABLES in INFORMATION_SCHEMA, so don't try. */ + /* Can't LOCK TABLES in I_S / P_S, so don't try. */ if (lock_tables && - !(mysql_get_server_version(mysql) >= 50003 && - !my_strcasecmp(&my_charset_latin1, db, "information_schema"))) + !(mysql_get_server_version(mysql) >= FIRST_INFORMATION_SCHEMA_VERSION && + !my_strcasecmp(&my_charset_latin1, db, INFORMATION_SCHEMA_DB_NAME)) && + !(mysql_get_server_version(mysql) >= FIRST_PERFORMANCE_SCHEMA_VERSION && + !my_strcasecmp(&my_charset_latin1, db, PERFORMANCE_SCHEMA_DB_NAME))) { if (mysql_real_query(mysql, lock_tables_query.str, lock_tables_query.length-1)) @@ -4612,6 +4641,8 @@ static int dump_selected_tables(char *db, char **table_names, int tables) DB_error(mysql, "when doing refresh"); } /* We shall countinue here, if --force was given */ + else + verbose_msg("-- dump_selected_tables : logs flushed successfully!\n"); } if (opt_xml) print_xml_tag(md_result_file, "", "\n", "database", "name=", db, NullS); @@ -4651,7 +4682,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) dump_routines_for_db(db); } free_root(&root, MYF(0)); - my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); + my_free(order_by); order_by= 0; if (opt_xml) { @@ -4659,7 +4690,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) check_io(md_result_file); } if (lock_tables) - VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES")); + (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"); DBUG_RETURN(0); } /* dump_selected_tables */ @@ -4667,7 +4698,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos) { MYSQL_ROW row; - MYSQL_RES *master; + MYSQL_RES *UNINIT_VAR(master); char binlog_pos_file[FN_REFLEN]; char binlog_pos_offset[LONGLONG_LEN+1]; char *file, *offset; @@ -4698,8 +4729,8 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos) if (!ignore_errors) { /* SHOW MASTER STATUS reports nothing and --force is not enabled */ - my_printf_error(0, "Error: Binlogging on server not active", - MYF(0)); + fprintf(stderr, "%s: Error: Binlogging on server not active\n", + my_progname_short); maybe_exit(EX_MYSQLERR); return 1; } @@ -4711,10 +4742,9 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos) } /* SHOW MASTER STATUS reports file and position */ - if (opt_comments) - print_comment(md_result_file, 0, - "\n--\n-- Position to start replication or point-in-time " - "recovery from\n--\n\n"); + print_comment(md_result_file, 0, + "\n--\n-- Position to start replication or point-in-time " + "recovery from\n--\n\n"); fprintf(md_result_file, "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", comment_prefix, file, offset); @@ -4726,6 +4756,130 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos) return 0; } +static int do_stop_slave_sql(MYSQL *mysql_con) +{ + MYSQL_RES *slave; + /* We need to check if the slave sql is running in the first place */ + if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS")) + return(1); + else + { + MYSQL_ROW row= mysql_fetch_row(slave); + if (row && row[11]) + { + /* if SLAVE SQL is not running, we don't stop it */ + if (!strcmp(row[11],"No")) + { + mysql_free_result(slave); + /* Silently assume that they don't have the slave running */ + return(0); + } + } + } + mysql_free_result(slave); + + /* now, stop slave if running */ + if (mysql_query_with_error_report(mysql_con, 0, "STOP SLAVE SQL_THREAD")) + return(1); + + return(0); +} + +static int add_stop_slave(void) +{ + if (opt_comments) + fprintf(md_result_file, + "\n--\n-- stop slave statement to make a recovery dump)\n--\n\n"); + fprintf(md_result_file, "STOP SLAVE;\n"); + return(0); +} + +static int add_slave_statements(void) +{ + if (opt_comments) + fprintf(md_result_file, + "\n--\n-- start slave statement to make a recovery dump)\n--\n\n"); + fprintf(md_result_file, "START SLAVE;\n"); + return(0); +} + +static int do_show_slave_status(MYSQL *mysql_con) +{ + MYSQL_RES *slave= 0; + const char *comment_prefix= + (opt_slave_data == MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL) ? "-- " : ""; + if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS")) + { + if (!ignore_errors) + { + /* SHOW SLAVE STATUS reports nothing and --force is not enabled */ + fprintf(stderr, "%s: Error: Slave not set up\n", my_progname_short); + } + mysql_free_result(slave); + return 1; + } + else + { + MYSQL_ROW row= mysql_fetch_row(slave); + if (row && row[9] && row[21]) + { + /* SHOW MASTER STATUS reports file and position */ + if (opt_comments) + fprintf(md_result_file, + "\n--\n-- Position to start replication or point-in-time " + "recovery from (the master of this slave)\n--\n\n"); + + fprintf(md_result_file, "%sCHANGE MASTER TO ", comment_prefix); + + if (opt_include_master_host_port) + { + if (row[1]) + fprintf(md_result_file, "MASTER_HOST='%s', ", row[1]); + if (row[3]) + fprintf(md_result_file, "MASTER_PORT=%s, ", row[3]); + } + fprintf(md_result_file, + "MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", row[9], row[21]); + + check_io(md_result_file); + } + mysql_free_result(slave); + } + return 0; +} + +static int do_start_slave_sql(MYSQL *mysql_con) +{ + MYSQL_RES *slave; + /* We need to check if the slave sql is stopped in the first place */ + if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS")) + return(1); + else + { + MYSQL_ROW row= mysql_fetch_row(slave); + if (row && row[11]) + { + /* if SLAVE SQL is not running, we don't start it */ + if (!strcmp(row[11],"Yes")) + { + mysql_free_result(slave); + /* Silently assume that they don't have the slave running */ + return(0); + } + } + } + mysql_free_result(slave); + + /* now, start slave if stopped */ + if (mysql_query_with_error_report(mysql_con, 0, "START SLAVE")) + { + fprintf(stderr, "%s: Error: Unable to start slave\n", my_progname_short); + return 1; + } + return(0); +} + + static int do_flush_tables_read_lock(MYSQL *mysql_con) { @@ -4792,6 +4946,7 @@ static int purge_bin_logs_to(MYSQL *mysql_con, char* log_name) static int start_transaction(MYSQL *mysql_con) { + verbose_msg("-- Starting transaction...\n"); /* We use BEGIN for old servers. --single-transaction --master-data will fail on old servers, but that's ok as it was already silently broken (it didn't @@ -4846,7 +5001,7 @@ static ulong find_set(TYPELIB *lib, const char *x, uint length, for (; pos != end && *pos != ','; pos++) ; var_len= (uint) (pos - start); strmake(buff, start, min(sizeof(buff) - 1, var_len)); - find= find_type(buff, lib, var_len); + find= find_type(buff, lib, FIND_TYPE_BASIC); if (!find) { *err_pos= (char*) start; @@ -5360,8 +5515,9 @@ int main(int argc, char **argv) char bin_log_name[FN_REFLEN]; int exit_code; int consistent_binlog_pos= 0; - MY_INIT("mysqldump"); + MY_INIT(argv[0]); + sf_leaking_memory=1; /* don't report memory leaks on early exits */ compatible_mode_normal_str[0]= 0; default_charset= (char *)mysql_universal_client_charset; bzero((char*) &ignore_table, sizeof(ignore_table)); @@ -5372,6 +5528,7 @@ int main(int argc, char **argv) free_resources(); exit(exit_code); } + sf_leaking_memory=0; /* from now on we cleanup properly */ /* Disable comments in xml mode if 'comments' option is not explicitly used. @@ -5396,38 +5553,64 @@ int main(int argc, char **argv) if (!path) write_header(md_result_file, *argv); + if (opt_slave_data && do_stop_slave_sql(mysql)) + goto err; + if (opt_single_transaction && opt_master_data) { /* See if we can avoid FLUSH TABLES WITH READ LOCK (MariaDB 5.3+). */ consistent_binlog_pos= check_consistent_binlog_pos(NULL, NULL); } - if ((opt_lock_all_tables || (opt_master_data && !consistent_binlog_pos)) && + if ((opt_lock_all_tables || (opt_master_data && !consistent_binlog_pos) || + (opt_single_transaction && flush_logs)) && do_flush_tables_read_lock(mysql)) goto err; - if (opt_single_transaction && start_transaction(mysql)) - goto err; - if (opt_delete_master_logs) + + /* + Flush logs before starting transaction since + this causes implicit commit starting mysql-5.5. + */ + if (opt_lock_all_tables || opt_master_data || + (opt_single_transaction && flush_logs) || + opt_delete_master_logs) { - if (mysql_refresh(mysql, REFRESH_LOG) || - get_bin_log_name(mysql, bin_log_name, sizeof(bin_log_name))) - goto err; + if (flush_logs || opt_delete_master_logs) + { + if (mysql_refresh(mysql, REFRESH_LOG)) + goto err; + verbose_msg("-- main : logs flushed successfully!\n"); + } + + /* Not anymore! That would not be sensible. */ flush_logs= 0; } - if (opt_lock_all_tables || opt_master_data) + + if (opt_delete_master_logs) { - if (flush_logs && mysql_refresh(mysql, REFRESH_LOG)) + if (get_bin_log_name(mysql, bin_log_name, sizeof(bin_log_name))) goto err; - flush_logs= 0; /* not anymore; that would not be sensible */ } + + if (opt_single_transaction && start_transaction(mysql)) + goto err; + + /* Add 'STOP SLAVE to beginning of dump */ + if (opt_slave_apply && add_stop_slave()) + goto err; if (opt_master_data && do_show_master_status(mysql, consistent_binlog_pos)) goto err; + if (opt_slave_data && do_show_slave_status(mysql)) + goto err; if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */ goto err; if (opt_alltspcs) dump_all_tablespaces(); + if (extended_insert) + init_dynamic_string_checked(&extended_row, "", 1024, 1024); + if (opt_alldbs) { if (!opt_alltspcs && !opt_notspcs) @@ -5449,6 +5632,14 @@ int main(int argc, char **argv) dump_databases(argv); } + /* if --dump-slave , start the slave sql thread */ + if (opt_slave_data && do_start_slave_sql(mysql)) + goto err; + + /* add 'START SLAVE' to end of dump */ + if (opt_slave_apply && add_slave_statements()) + goto err; + /* ensure dumped data flushed */ if (md_result_file && fflush(md_result_file)) { @@ -5461,7 +5652,7 @@ int main(int argc, char **argv) goto err; #ifdef HAVE_SMEM - my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); + my_free(shared_memory_base_name); #endif /* No reason to explicitely COMMIT the transaction, neither to explicitely diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 0067f5b3a8b..77d0cd0a7d3 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -59,23 +59,21 @@ static char *opt_password=0, *current_user=0, *current_host=0, *current_db=0, *fields_terminated=0, *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0, *opt_columns=0, - *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; + *default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME; static uint opt_mysql_port= 0, opt_protocol= 0; static char * opt_mysql_unix_port=0; +static char *opt_plugin_dir= 0, *opt_default_auth= 0; static longlong opt_ignore_lines= -1; -static CHARSET_INFO *charset_info= &my_charset_latin1; #include <sslopt-vars.h> +static char **argv_to_free; + #ifdef HAVE_SMEM static char *shared_memory_base_name=0; #endif static struct my_option my_long_options[] = { -#ifdef __NETWARE__ - {"autoclose", OPT_AUTO_CLOSE, "Automatically 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, "Directory for character set files.", (char**) &charsets_dir, (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -97,6 +95,10 @@ static struct my_option my_long_options[] = {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", &debug_info_flag, &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"default_auth", OPT_DEFAULT_AUTH, + "Default authentication client-side plugin to use.", + &opt_default_auth, &opt_default_auth, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"delete", 'd', "First delete all rows from table.", &opt_delete, &opt_delete, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"fields-terminated-by", OPT_FTB, @@ -146,6 +148,9 @@ static struct my_option my_long_options[] = {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", + &opt_plugin_dir, &opt_plugin_dir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection or 0 for default to, in " "order of preference, my.cnf, $MYSQL_TCP_PORT, " #if MYSQL_PORT_DEFAULT == 0 @@ -190,13 +195,11 @@ static struct my_option my_long_options[] = static const char *load_default_groups[]= { "mysqlimport","client", "client-server", "client-mariadb", 0 }; -#include <help_start.h> static void print_version(void) { printf("%s Ver %s Distrib %s, for %s (%s)\n" ,my_progname, IMPORT_VERSION, MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); - NETWARE_SET_SCREEN_MODE(1); } @@ -219,25 +222,19 @@ file. The SQL command 'LOAD DATA INFILE' is used to import the rows.\n"); my_print_variables(my_long_options); } -#include <help_end.h> static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) { switch(optid) { -#ifdef __NETWARE__ - case OPT_AUTO_CLOSE: - setscreenmode(SCR_AUTOCLOSE_ON_EXIT); - break; -#endif case 'p': if (argument == disabled_my_option) argument= (char*) ""; /* Don't require password */ if (argument) { char *start=argument; - my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); + my_free(opt_password); opt_password=my_strdup(argument,MYF(MY_FAE)); while (*argument) *argument++= 'x'; /* Destroy argument */ if (*start) @@ -293,10 +290,6 @@ static int get_options(int *argc, char ***argv) fprintf(stderr, "You can't use --ignore (-i) and --replace (-r) at the same time.\n"); return(1); } - if (strcmp(default_charset, charset_info->csname) && - !(charset_info= get_charset_by_csname(default_charset, - MY_CS_PRIMARY, MYF(MY_WME)))) - exit(1); if (*argc < 2) { usage(); @@ -451,6 +444,14 @@ static MYSQL *db_connect(char *host, char *database, if (shared_memory_base_name) mysql_options(mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); #endif + + if (opt_plugin_dir && *opt_plugin_dir) + mysql_options(mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir); + + if (opt_default_auth && *opt_default_auth) + mysql_options(mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset); if (!(mysql_real_connect(mysql,host,user,passwd, database,opt_mysql_port,opt_mysql_unix_port, 0))) @@ -482,10 +483,18 @@ static void db_disconnect(char *host, MYSQL *mysql) static void safe_exit(int error, MYSQL *mysql) { - if (ignore_errors) + if (error && ignore_errors) return; if (mysql) mysql_close(mysql); + +#ifdef HAVE_SMEM + my_free(shared_memory_base_name); +#endif + free_defaults(argv_to_free); + mysql_library_end(); + my_free(opt_password); + my_end(my_end_arg); exit(error); } @@ -604,10 +613,11 @@ error: int main(int argc, char **argv) { int error=0; - char **argv_to_free; MY_INIT(argv[0]); + sf_leaking_memory=1; /* don't report memory leaks on early exits */ - load_defaults("my",load_default_groups,&argc,&argv); + if (load_defaults("my",load_default_groups,&argc,&argv)) + return 1; /* argv is changed in the program */ argv_to_free= argv; if (get_options(&argc, &argv)) @@ -615,6 +625,7 @@ int main(int argc, char **argv) free_defaults(argv_to_free); return(1); } + sf_leaking_memory=0; /* from now on we cleanup properly */ #ifdef HAVE_LIBPTHREAD if (opt_use_threads && !lock_tables) @@ -625,8 +636,8 @@ int main(int argc, char **argv) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - VOID(pthread_mutex_init(&counter_mutex, NULL)); - VOID(pthread_cond_init(&count_threshhold, NULL)); + pthread_mutex_init(&counter_mutex, NULL); + pthread_cond_init(&count_threshhold, NULL); for (counter= 0; *argv != NULL; argv++) /* Loop through tables */ { @@ -665,8 +676,8 @@ int main(int argc, char **argv) pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime); } pthread_mutex_unlock(&counter_mutex); - VOID(pthread_mutex_destroy(&counter_mutex)); - VOID(pthread_cond_destroy(&count_threshhold)); + pthread_mutex_destroy(&counter_mutex); + pthread_cond_destroy(&count_threshhold); pthread_attr_destroy(&attr); } else @@ -693,11 +704,6 @@ int main(int argc, char **argv) exitcode= error; db_disconnect(current_host, mysql); } - my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); -#ifdef HAVE_SMEM - my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); -#endif - free_defaults(argv_to_free); - my_end(my_end_arg); + safe_exit(0, 0); return(exitcode); } diff --git a/client/mysqlshow.c b/client/mysqlshow.c index 7d73c0108cf..323c4282ff4 100644 --- a/client/mysqlshow.c +++ b/client/mysqlshow.c @@ -1,5 +1,6 @@ /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. + Copyright (c) 2010, 2012, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,7 +36,8 @@ static my_bool tty_password= 0, opt_table_type= 0; static my_bool debug_info_flag= 0, debug_check_flag= 0; static uint my_end_arg= 0; static uint opt_verbose=0; -static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; +static char *default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME; +static char *opt_plugin_dir= 0, *opt_default_auth= 0; #ifdef HAVE_SMEM static char *shared_memory_base_name=0; @@ -67,9 +69,13 @@ int main(int argc, char **argv) char *wild; MYSQL mysql; MY_INIT(argv[0]); - load_defaults("my",load_default_groups,&argc,&argv); + sf_leaking_memory=1; /* don't report memory leaks on early exits */ + if (load_defaults("my",load_default_groups,&argc,&argv)) + exit(1); + get_options(&argc,&argv); + sf_leaking_memory=0; /* from now on we cleanup properly */ wild=0; if (argc) { @@ -125,6 +131,12 @@ int main(int argc, char **argv) #endif mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); + if (opt_plugin_dir && *opt_plugin_dir) + mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir); + + if (opt_default_auth && *opt_default_auth) + mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + if (!(mysql_real_connect(&mysql,host,user,opt_password, (first_argument_uses_wildcards) ? "" : argv[0],opt_mysql_port,opt_mysql_unix_port, @@ -151,10 +163,9 @@ int main(int argc, char **argv) break; } mysql_close(&mysql); /* Close & free connection */ - if (opt_password) - my_free(opt_password,MYF(0)); + my_free(opt_password); #ifdef HAVE_SMEM - my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); + my_free(shared_memory_base_name); #endif my_end(my_end_arg); exit(error ? 1 : 0); @@ -163,10 +174,6 @@ int main(int argc, char **argv) static struct my_option my_long_options[] = { -#ifdef __NETWARE__ - {"autoclose", OPT_AUTO_CLOSE, "Automatically 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 for character set files.", (char**) &charsets_dir, (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -188,6 +195,10 @@ static struct my_option my_long_options[] = {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", &debug_info_flag, &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"default_auth", OPT_DEFAULT_AUTH, + "Default authentication client-side plugin to use.", + &opt_default_auth, &opt_default_auth, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"host", 'h', "Connect to host.", &host, &host, 0, GET_STR, @@ -201,6 +212,9 @@ static struct my_option my_long_options[] = "Password to use when connecting to server. If password is not given, it's " "solicited on the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", + &opt_plugin_dir, &opt_plugin_dir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection or 0 for default to, in " "order of preference, my.cnf, $MYSQL_TCP_PORT, " #if MYSQL_PORT_DEFAULT == 0 @@ -243,14 +257,11 @@ static struct my_option my_long_options[] = {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; - -#include <help_start.h> static void print_version(void) { printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,SHOW_VERSION, MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); - NETWARE_SET_SCREEN_MODE(1); } @@ -272,18 +283,12 @@ are shown."); my_print_variables(my_long_options); } -#include <help_end.h> static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) { switch(optid) { -#ifdef __NETWARE__ - case OPT_AUTO_CLOSE: - setscreenmode(SCR_AUTOCLOSE_ON_EXIT); - break; -#endif case 'v': opt_verbose++; break; @@ -293,7 +298,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), if (argument) { char *start=argument; - my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); + my_free(opt_password); opt_password=my_strdup(argument,MYF(MY_FAE)); while (*argument) *argument++= 'x'; /* Destroy argument */ if (*start) diff --git a/client/mysqlslap.c b/client/mysqlslap.c index f568ef9d2e2..8e70a2609c3 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -13,12 +13,8 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - original idea: Brian Aker via playing with ab for too many years - coded by: Patrick Galbraith */ - /* MySQL Slap @@ -128,6 +124,7 @@ static char *host= NULL, *opt_password= NULL, *user= NULL, *pre_system= NULL, *post_system= NULL, *opt_mysql_unix_port= NULL; +static char *opt_plugin_dir= 0, *opt_default_auth= 0; const char *delimiter= "\n"; @@ -321,8 +318,13 @@ int main(int argc, char **argv) option_string *eptr; MY_INIT(argv[0]); + sf_leaking_memory=1; /* don't report memory leaks on early exits */ - load_defaults("my",load_default_groups,&argc,&argv); + if (load_defaults("my",load_default_groups,&argc,&argv)) + { + my_end(0); + exit(1); + } defaults_argv=argv; if (get_options(&argc,&argv)) { @@ -330,6 +332,7 @@ int main(int argc, char **argv) my_end(0); exit(1); } + sf_leaking_memory=0; /* from now on we cleanup properly */ /* Seed the random number generator if we will be using it. */ if (auto_generate_sql) @@ -348,6 +351,12 @@ int main(int argc, char **argv) mysql_init(&mysql); set_mysql_connect_options(&mysql); + if (opt_plugin_dir && *opt_plugin_dir) + mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir); + + if (opt_default_auth && *opt_default_auth) + mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); + if (!opt_only_print) { if (!(mysql_real_connect(&mysql, host, user, opt_password, @@ -362,10 +371,10 @@ int main(int argc, char **argv) } } - VOID(pthread_mutex_init(&counter_mutex, NULL)); - VOID(pthread_cond_init(&count_threshhold, NULL)); - VOID(pthread_mutex_init(&sleeper_mutex, NULL)); - VOID(pthread_cond_init(&sleep_threshhold, NULL)); + pthread_mutex_init(&counter_mutex, NULL); + pthread_cond_init(&count_threshhold, NULL); + pthread_mutex_init(&sleeper_mutex, NULL); + pthread_cond_init(&sleep_threshhold, NULL); /* Main iterations loop */ eptr= engine_options; @@ -396,19 +405,17 @@ int main(int argc, char **argv) } while (eptr ? (eptr= eptr->next) : 0); - VOID(pthread_mutex_destroy(&counter_mutex)); - VOID(pthread_cond_destroy(&count_threshhold)); - VOID(pthread_mutex_destroy(&sleeper_mutex)); - VOID(pthread_cond_destroy(&sleep_threshhold)); + pthread_mutex_destroy(&counter_mutex); + pthread_cond_destroy(&count_threshhold); + pthread_mutex_destroy(&sleeper_mutex); + pthread_cond_destroy(&sleep_threshhold); if (!opt_only_print) mysql_close(&mysql); /* Close & free connection */ /* now free all the strings we created */ - if (opt_password) - my_free(opt_password, MYF(0)); - - my_free(concurrency, MYF(0)); + my_free(opt_password); + my_free(concurrency); statement_cleanup(create_statements); statement_cleanup(query_statements); @@ -417,10 +424,10 @@ int main(int argc, char **argv) option_cleanup(engine_options); #ifdef HAVE_SMEM - if (shared_memory_base_name) - my_free(shared_memory_base_name, MYF(MY_ALLOW_ZERO_PTR)); + my_free(shared_memory_base_name); #endif free_defaults(defaults_argv); + mysql_library_end(); my_end(my_end_arg); return 0; @@ -518,7 +525,7 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) if (opt_csv_str) print_conclusions_csv(&conclusion); - my_free(head_sptr, MYF(0)); + my_free(head_sptr); } @@ -602,6 +609,10 @@ static struct my_option my_long_options[] = GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"debug-info", 'T', "Print some debug info at exit.", &debug_info_flag, &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"default_auth", OPT_DEFAULT_AUTH, + "Default authentication client-side plugin to use.", + &opt_default_auth, &opt_default_auth, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"delimiter", 'F', "Delimiter to use in SQL statements supplied in file or command line.", (char**) &delimiter, (char**) &delimiter, 0, GET_STR, REQUIRED_ARG, @@ -646,6 +657,9 @@ static struct my_option my_long_options[] = {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif + {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", + &opt_plugin_dir, &opt_plugin_dir, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection.", &opt_mysql_port, &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, @@ -698,8 +712,6 @@ static struct my_option my_long_options[] = }; -#include <help_start.h> - static void print_version(void) { printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname, SLAP_VERSION, @@ -717,7 +729,6 @@ static void usage(void) my_print_help(my_long_options); } -#include <help_end.h> static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), @@ -725,11 +736,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), { DBUG_ENTER("get_one_option"); switch(optid) { -#ifdef __NETWARE__ - case OPT_AUTO_CLOSE: - setscreenmode(SCR_AUTOCLOSE_ON_EXIT); - break; -#endif case 'v': verbose++; break; @@ -739,7 +745,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), if (argument) { char *start= argument; - my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); + my_free(opt_password); opt_password= my_strdup(argument,MYF(MY_FAE)); while (*argument) *argument++= 'x'; /* Destroy argument */ if (*start) @@ -1390,7 +1396,7 @@ get_options(int *argc,char ***argv) tmp_string[sbuf.st_size]= '\0'; my_close(data_file,MYF(0)); parse_delimiter(tmp_string, &create_statements, delimiter[0]); - my_free(tmp_string, MYF(0)); + my_free(tmp_string); } else if (create_string) { @@ -1419,7 +1425,7 @@ get_options(int *argc,char ***argv) if (user_supplied_query) actual_queries= parse_delimiter(tmp_string, &query_statements, delimiter[0]); - my_free(tmp_string, MYF(0)); + my_free(tmp_string); } else if (user_supplied_query) { @@ -1450,7 +1456,7 @@ get_options(int *argc,char ***argv) if (user_supplied_pre_statements) (void)parse_delimiter(tmp_string, &pre_statements, delimiter[0]); - my_free(tmp_string, MYF(0)); + my_free(tmp_string); } else if (user_supplied_pre_statements) { @@ -1481,7 +1487,7 @@ get_options(int *argc,char ***argv) if (user_supplied_post_statements) (void)parse_delimiter(tmp_string, &post_statements, delimiter[0]); - my_free(tmp_string, MYF(0)); + my_free(tmp_string); } else if (user_supplied_post_statements) { @@ -1585,9 +1591,9 @@ drop_primary_key_list(void) if (primary_keys_number_of) { for (counter= 0; counter < primary_keys_number_of; counter++) - my_free(primary_keys[counter], MYF(0)); + my_free(primary_keys[counter]); - my_free(primary_keys, MYF(0)); + my_free(primary_keys); } return 0; @@ -2204,11 +2210,9 @@ option_cleanup(option_string *stmt) for (ptr= stmt; ptr; ptr= nptr) { nptr= ptr->next; - if (ptr->string) - my_free(ptr->string, MYF(0)); - if (ptr->option) - my_free(ptr->option, MYF(0)); - my_free(ptr, MYF(0)); + my_free(ptr->string); + my_free(ptr->option); + my_free(ptr); } } @@ -2222,9 +2226,8 @@ statement_cleanup(statement *stmt) for (ptr= stmt; ptr; ptr= nptr) { nptr= ptr->next; - if (ptr->string) - my_free(ptr->string, MYF(0)); - my_free(ptr, MYF(0)); + my_free(ptr->string); + my_free(ptr); } } diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 2cf3faae0b6..5415b653615 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 2009, 2012 Monty Program Ab. + Copyright (c) 2009, 2012, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,8 +12,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* mysqltest @@ -34,7 +33,7 @@ And many others */ -#define MTEST_VERSION "3.3" +#define MTEST_VERSION "3.4" #include "client_priv.h" #include <mysql_version.h> @@ -64,6 +63,12 @@ #define SIGNAL_FMT "signal %d" #endif +static my_bool non_blocking_api_enabled= 0; +#if !defined(EMBEDDED_LIBRARY) +#define WRAP_NONBLOCK_ENABLED non_blocking_api_enabled +#include "../tests/nonblock-wrappers.h" +#endif + /* Use cygwin for --exec and --system before 5.0 */ #if MYSQL_VERSION_ID < 50000 #define USE_CYGWIN @@ -75,6 +80,8 @@ #define MAX_DELIMITER_LENGTH 16 #define DEFAULT_MAX_CONN 64 +#define DIE_BUFF_SIZE 8192 + /* Flags controlling send and reap */ #define QUERY_SEND_FLAG 1 #define QUERY_REAP_FLAG 2 @@ -83,27 +90,28 @@ static int setenv(const char *name, const char *value, int overwrite); #endif +C_MODE_START +static sig_handler signal_handler(int sig); +static my_bool get_one_option(int optid, const struct my_option *, + char *argument); +C_MODE_END + enum { - OPT_SKIP_SAFEMALLOC=OPT_MAX_CLIENT_OPTION, - OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, - OPT_MAX_CONNECT_RETRIES, OPT_MAX_CONNECTIONS, - OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES, - OPT_GLOBAL_SUBST, OPT_MY_CONNECT_TIMEOUT + OPT_LOG_DIR=OPT_MAX_CLIENT_OPTION, OPT_RESULT_FORMAT_VERSION }; static int record= 0, opt_sleep= -1; static char *opt_db= 0, *opt_pass= 0; const char *opt_user= 0, *opt_host= 0, *unix_sock= 0, *opt_basedir= "./"; -#ifdef HAVE_SMEM static char *shared_memory_base_name=0; -#endif const char *opt_logdir= ""; -const char *opt_include= 0, *opt_charsets_dir; +const char *opt_prologue= 0, *opt_charsets_dir; static int opt_port= 0; static int opt_max_connect_retries; +static int opt_result_format_version; static int opt_max_connections= DEFAULT_MAX_CONN; +static int error_count= 0; static my_bool opt_compress= 0, silent= 0, verbose= 0; -static int opt_connect_timeout= -1; static my_bool debug_info_flag= 0, debug_check_flag= 0; static my_bool tty_password= 0; static my_bool opt_mark_progress= 0; @@ -119,8 +127,7 @@ static my_bool disable_connect_log= 1; static my_bool disable_warnings= 0, disable_column_names= 0; static my_bool prepare_warnings_enabled= 0; static my_bool disable_info= 1; -static char *opt_plugin_dir= 0, *opt_default_auth; -static my_bool abort_on_error= 1; +static my_bool abort_on_error= 1, opt_continue_on_error= 0; static my_bool server_initialized= 0; static my_bool is_windows= 0; static char **default_argv; @@ -128,12 +135,49 @@ static const char *load_default_groups[]= { "mysqltest", "client", "client-server", "client-mariadb", 0 }; static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer; +/* Info on properties that can be set with --enable_X and --disable_X */ + +struct property { + my_bool *var; /* Actual variable */ + my_bool set; /* Has been set for ONE command */ + my_bool old; /* If set, thus is the old value */ + my_bool reverse; /* Varible is true if disabled */ + const char *env_name; /* Env. variable name */ +}; + +static struct property prop_list[] = { + { &abort_on_error, 0, 1, 0, "$ENABLED_ABORT_ON_ERROR" }, + { &disable_connect_log, 0, 1, 1, "$ENABLED_CONNECT_LOG" }, + { &disable_info, 0, 1, 1, "$ENABLED_INFO" }, + { &display_metadata, 0, 0, 0, "$ENABLED_METADATA" }, + { &ps_protocol_enabled, 0, 0, 0, "$ENABLED_PS_PROTOCOL" }, + { &disable_query_log, 0, 0, 1, "$ENABLED_QUERY_LOG" }, + { &disable_result_log, 0, 0, 1, "$ENABLED_RESULT_LOG" }, + { &disable_warnings, 0, 0, 1, "$ENABLED_WARNINGS" } +}; + +static my_bool once_property= FALSE; + +enum enum_prop { + P_ABORT= 0, + P_CONNECT, + P_INFO, + P_META, + P_PS, + P_QUERY, + P_RESULT, + P_WARN, + P_MAX +}; + static uint start_lineno= 0; /* Start line of current command */ static uint my_end_arg= 0; /* Number of lines of the result to include in failure report */ static uint opt_tail_lines= 0; +static uint opt_connect_timeout= 0; + static char delimiter[MAX_DELIMITER_LENGTH]= ";"; static uint delimiter_length= 1; @@ -165,7 +209,7 @@ static struct st_block *cur_block, *block_stack_end; struct st_test_file { FILE* file; - const char *file_name; + char *file_name; uint lineno; /* Current line in file */ }; @@ -173,7 +217,6 @@ static struct st_test_file file_stack[16]; static struct st_test_file* cur_file; static struct st_test_file* file_stack_end; - static CHARSET_INFO *charset_info= &my_charset_latin1; /* Default charset */ static const char *embedded_server_groups[]= @@ -199,6 +242,10 @@ static ulonglong timer_now(void); static ulong connection_retry_sleep= 100000; /* Microseconds */ +static const char *opt_plugin_dir; +static const char *opt_suite_dir, *opt_overlay_dir; +static size_t suite_dir_len, overlay_dir_len; + /* Precompiled re's */ static my_regex_t ps_re; /* the query can be run using PS protocol */ static my_regex_t sp_re; /* the query can be run as a SP */ @@ -240,8 +287,9 @@ typedef struct int str_val_len; int int_val; int alloced_len; - int int_dirty; /* do not update string if int is updated until first read */ - int alloced; + bool int_dirty; /* do not update string if int is updated until first read */ + bool is_int; + bool alloced; } VAR; /*Perl/shell-like variable registers */ @@ -261,13 +309,16 @@ struct st_connection my_bool pending; #ifdef EMBEDDED_LIBRARY + pthread_t tid; const char *cur_query; int cur_query_len; - pthread_mutex_t mutex; - pthread_cond_t cond; - pthread_t tid; + int command, result; + pthread_mutex_t query_mutex; + pthread_cond_t query_cond; + pthread_mutex_t result_mutex; + pthread_cond_t result_cond; int query_done; - my_bool has_thread, mutex_inited; + my_bool has_thread; #endif /*EMBEDDED_LIBRARY*/ }; @@ -294,8 +345,7 @@ enum enum_commands { Q_SEND, Q_REAP, Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN, Q_PING, Q_EVAL, - Q_RPL_PROBE, Q_ENABLE_RPL_PARSE, - Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT, + Q_EVAL_RESULT, Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG, Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG, Q_ENABLE_CONNECT_LOG, Q_DISABLE_CONNECT_LOG, @@ -311,6 +361,7 @@ enum enum_commands { Q_LOWERCASE, Q_START_TIMER, Q_END_TIMER, Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL, + Q_ENABLE_NON_BLOCKING_API, Q_DISABLE_NON_BLOCKING_API, Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT, Q_IF, Q_DISABLE_PARSING, Q_ENABLE_PARSING, @@ -320,12 +371,13 @@ enum enum_commands { Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR, Q_LIST_FILES, Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE, Q_SEND_SHUTDOWN, Q_SHUTDOWN_SERVER, + Q_RESULT_FORMAT_VERSION, Q_MOVE_FILE, Q_REMOVE_FILES_WILDCARD, Q_SEND_EVAL, Q_ENABLE_PREPARE_WARNINGS, Q_DISABLE_PREPARE_WARNINGS, - Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ - Q_COMMENT_WITH_COMMAND + Q_COMMENT_WITH_COMMAND, + Q_EMPTY_LINE }; @@ -358,9 +410,6 @@ const char *command_names[]= "replace_column", "ping", "eval", - "rpl_probe", - "enable_rpl_parse", - "disable_rpl_parse", "eval_result", /* Enable/disable that the _query_ is logged to result file */ "enable_query_log", @@ -394,6 +443,8 @@ const char *command_names[]= "character_set", "disable_ps_protocol", "enable_ps_protocol", + "enable_non_blocking_api", + "disable_non_blocking_api", "disable_reconnect", "enable_reconnect", "if", @@ -423,6 +474,7 @@ const char *command_names[]= "list_files_append_file", "send_shutdown", "shutdown_server", + "result_format", "move_file", "remove_files_wildcard", "send_eval", @@ -479,28 +531,56 @@ TYPELIB command_typelib= {array_elements(command_names),"", command_names, 0}; DYNAMIC_STRING ds_res; +/* Points to ds_warning in run_query, so it can be freed */ +DYNAMIC_STRING *ds_warn= 0; struct st_command *curr_command= 0; char builtin_echo[FN_REFLEN]; +struct st_replace_regex +{ +DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */ + +/* +Temporary storage areas for substitutions. To reduce unnessary copying +and memory freeing/allocation, we pre-allocate two buffers, and alternate +their use, one for input/one for output, the roles changing on the next +st_regex substition. At the end of substitutions buf points to the +one containing the final result. +*/ +char* buf; +char* even_buf; +char* odd_buf; +int even_buf_len; +int odd_buf_len; +}; + +struct st_replace_regex *glob_replace_regex= 0; + +struct st_replace; +struct st_replace *glob_replace= 0; +void replace_strings_append(struct st_replace *rep, DYNAMIC_STRING* ds, +const char *from, int len); + static void cleanup_and_exit(int exit_code) __attribute__((noreturn)); -void die(const char *fmt, ...) - ATTRIBUTE_FORMAT(printf, 1, 2) __attribute__((noreturn)); -void abort_not_supported_test(const char *fmt, ...) - ATTRIBUTE_FORMAT(printf, 1, 2) __attribute__((noreturn)); -void verbose_msg(const char *fmt, ...) - ATTRIBUTE_FORMAT(printf, 1, 2); -void log_msg(const char *fmt, ...) - ATTRIBUTE_FORMAT(printf, 1, 2); +void really_die(const char *msg) __attribute__((noreturn)); +void report_or_die(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2); +void die(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2) + __attribute__((noreturn)); +static void make_error_message(char *buf, size_t len, const char *fmt, va_list args); +void abort_not_supported_test(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2) + __attribute__((noreturn)); +void verbose_msg(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2); +void log_msg(const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 1, 2); VAR* var_from_env(const char *, const char *); VAR* var_init(VAR* v, const char *name, int name_len, const char *val, int val_len); -void var_free(void* v); VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, my_bool ignore_not_existing); -void eval_expr(VAR* v, const char *p, const char** p_end, bool do_eval= true); +void eval_expr(VAR* v, const char *p, const char** p_end, + bool open_end=false, bool do_eval=true); my_bool match_delimiter(int c, const char *delim, uint length); void dump_result_to_reject_file(char *buf, int size); void dump_warning_messages(); @@ -511,6 +591,8 @@ void str_to_file(const char *fname, char *str, int size); void str_to_file2(const char *fname, char *str, int size, my_bool append); void fix_win_paths(const char *val, int len); +const char *get_errname_from_code (uint error_code); +int multi_reg_replace(struct st_replace_regex* r,char* val); #ifdef __WIN__ void free_tmp_sh_file(); @@ -541,6 +623,8 @@ void free_all_replace(){ free_replace_column(); } +void var_set_int(const char* name, int value); + class LogFile { FILE* m_file; @@ -561,8 +645,7 @@ public: void open(const char* dir, const char* name, const char* ext) { DBUG_ENTER("LogFile::open"); - DBUG_PRINT("enter", ("dir: '%s', name: '%s'", - val_or_null(dir), val_or_null(name))); + DBUG_PRINT("enter", ("dir: '%s', name: '%s'", dir, name)); if (!name) { m_file= stdout; @@ -657,9 +740,8 @@ public: DBUG_VOID_RETURN; } - IF_DBUG(buf[bytes]= '\0';) - DBUG_PRINT("info", ("Read %lu bytes from file, buf: %s", - (unsigned long)bytes, buf)); + DBUG_PRINT("info", ("Read %zu bytes from file, buf: %.*s", + bytes, (int)bytes, buf)); char* show_from= buf + bytes; while(show_from > buf && lines > 0 ) @@ -722,14 +804,6 @@ public: LogFile log_file; LogFile progress_file; - -/* Disable functions that only exist in MySQL 4.0 */ -#if MYSQL_VERSION_ID < 40000 -void mysql_enable_rpl_parse(MYSQL* mysql __attribute__((unused))) {} -void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {} -int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { return 1; } -my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } -#endif void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, int len); void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val); @@ -744,12 +818,17 @@ void handle_error(struct st_command*, unsigned int err_errno, const char *err_error, const char *err_sqlstate, DYNAMIC_STRING *ds); void handle_no_error(struct st_command*); +void revert_properties(); static void handle_no_active_connection(struct st_command* command, struct st_connection *cn, DYNAMIC_STRING *ds); #ifdef EMBEDDED_LIBRARY +#define EMB_SEND_QUERY 1 +#define EMB_READ_QUERY_RESULT 2 +#define EMB_END_CONNECTION 3 + /* workaround for MySQL BUG#57491 */ #undef MY_WME #define MY_WME 0 @@ -757,90 +836,140 @@ static void handle_no_active_connection(struct st_command* command, /* attributes of the query thread */ pthread_attr_t cn_thd_attrib; + /* - send_one_query executes query in separate thread, which is - necessary in embedded library to run 'send' in proper way. - This implementation doesn't handle errors returned - by mysql_send_query. It's technically possible, though - I don't see where it is needed. + This procedure represents the connection and actually + runs queries when in the EMBEDDED-SERVER mode. + The run_query_normal() just sends request for running + mysql_send_query and mysql_read_query_result() here. */ -pthread_handler_t send_one_query(void *arg) + +pthread_handler_t connection_thread(void *arg) { struct st_connection *cn= (struct st_connection*)arg; - if (!cn->mysql) - return 0; - mysql_thread_init(); - VOID(mysql_send_query(cn->mysql, cn->cur_query, cn->cur_query_len)); + while (cn->command != EMB_END_CONNECTION) + { + if (!cn->command) + { + pthread_mutex_lock(&cn->query_mutex); + while (!cn->command) + pthread_cond_wait(&cn->query_cond, &cn->query_mutex); + pthread_mutex_unlock(&cn->query_mutex); + } + switch (cn->command) + { + case EMB_END_CONNECTION: + goto end_thread; + case EMB_SEND_QUERY: + cn->result= mysql_send_query(cn->mysql, cn->cur_query, cn->cur_query_len); + break; + case EMB_READ_QUERY_RESULT: + cn->result= mysql_read_query_result(cn->mysql); + break; + default: + DBUG_ASSERT(0); + } + cn->command= 0; + pthread_mutex_lock(&cn->result_mutex); + cn->query_done= 1; + pthread_cond_signal(&cn->result_cond); + pthread_mutex_unlock(&cn->result_mutex); + } - mysql_thread_end(); - pthread_mutex_lock(&cn->mutex); +end_thread: cn->query_done= 1; - VOID(pthread_cond_signal(&cn->cond)); - pthread_mutex_unlock(&cn->mutex); + mysql_thread_end(); pthread_exit(0); return 0; } -static int do_send_query(struct st_connection *cn, const char *q, int q_len, - int flags) +static void wait_query_thread_done(struct st_connection *con) { - if (!cn->mysql) - die("Trying to send a query without a connection"); + DBUG_ASSERT(con->has_thread); + if (!con->query_done) + { + pthread_mutex_lock(&con->result_mutex); + while (!con->query_done) + pthread_cond_wait(&con->result_cond, &con->result_mutex); + pthread_mutex_unlock(&con->result_mutex); + } +} - if (flags & QUERY_REAP_FLAG) - return mysql_send_query(cn->mysql, q, q_len); - if (!cn->mutex_inited && - (pthread_mutex_init(&cn->mutex, NULL) || - pthread_cond_init(&cn->cond, NULL))) - die("Error in the thread library"); +static void signal_connection_thd(struct st_connection *cn, int command) +{ + DBUG_ASSERT(cn->has_thread); + cn->query_done= 0; + cn->command= command; + pthread_mutex_lock(&cn->query_mutex); + pthread_cond_signal(&cn->query_cond); + pthread_mutex_unlock(&cn->query_mutex); +} + - cn->mutex_inited= 1; +/* + Sometimes we try to execute queries when the connection is closed. + It's done to make sure it was closed completely. + So that if our connection is closed (cn->has_thread == 0), we just return + the mysql_send_query() result which is an error in this case. +*/ + +static int do_send_query(struct st_connection *cn, const char *q, int q_len) +{ + if (!cn->has_thread) + return mysql_send_query(cn->mysql, q, q_len); cn->cur_query= q; cn->cur_query_len= q_len; - cn->query_done= 0; - if (pthread_create(&cn->tid, &cn_thd_attrib, send_one_query, (void*)cn)) - die("Cannot start new thread for query"); - - cn->has_thread= TRUE; + signal_connection_thd(cn, EMB_SEND_QUERY); return 0; } -static void wait_query_thread_end(struct st_connection *con) +static int do_read_query_result(struct st_connection *cn) { - if (!con->query_done) - { - pthread_mutex_lock(&con->mutex); - while (!con->query_done) - pthread_cond_wait(&con->cond, &con->mutex); - pthread_mutex_unlock(&con->mutex); - } - if (con->has_thread) - { -#ifndef __WIN__ - /* May hang on Windows, but the problem it solves is not seen there */ - pthread_join(con->tid, NULL); -#endif - con->has_thread= FALSE; - } + DBUG_ASSERT(cn->has_thread); + wait_query_thread_done(cn); + signal_connection_thd(cn, EMB_READ_QUERY_RESULT); + wait_query_thread_done(cn); + + return cn->result; } -static void free_embedded_data(struct st_connection *con) + +static void emb_close_connection(struct st_connection *cn) { - if (con->mutex_inited) - { - con->mutex_inited= 0; - pthread_mutex_destroy(&con->mutex); - pthread_cond_destroy(&con->cond); - } + if (!cn->has_thread) + return; + wait_query_thread_done(cn); + signal_connection_thd(cn, EMB_END_CONNECTION); + pthread_join(cn->tid, NULL); + cn->has_thread= FALSE; + pthread_mutex_destroy(&cn->query_mutex); + pthread_cond_destroy(&cn->query_cond); + pthread_mutex_destroy(&cn->result_mutex); + pthread_cond_destroy(&cn->result_cond); +} + + +static void init_connection_thd(struct st_connection *cn) +{ + cn->query_done= 1; + cn->command= 0; + if (pthread_mutex_init(&cn->query_mutex, NULL) || + pthread_cond_init(&cn->query_cond, NULL) || + pthread_mutex_init(&cn->result_mutex, NULL) || + pthread_cond_init(&cn->result_cond, NULL) || + pthread_create(&cn->tid, &cn_thd_attrib, connection_thread, (void*)cn)) + die("Error in the thread library"); + cn->has_thread=TRUE; } #else /*EMBEDDED_LIBRARY*/ -#define do_send_query(cn,q,q_len,flags) mysql_send_query(cn->mysql, q, q_len) -#define free_embedded_data(next_con) do { } while(0) +#define init_connection_thd(X) do { } while(0) +#define do_send_query(cn,q,q_len) mysql_send_query(cn->mysql, q, q_len) +#define do_read_query_result(cn) mysql_read_query_result(cn->mysql) #endif /*EMBEDDED_LIBRARY*/ @@ -865,7 +994,10 @@ void do_eval(DYNAMIC_STRING *query_eval, const char *query, else { if (!(v= var_get(p, &p, 0, 0))) - die("Bad variable in eval"); + { + report_or_die( "Bad variable in eval"); + return; + } dynstr_append_mem(query_eval, v->str_val, v->str_val_len); } break; @@ -1147,14 +1279,20 @@ void handle_command_error(struct st_command *command, uint error, { DBUG_ENTER("handle_command_error"); DBUG_PRINT("enter", ("error: %d", error)); + var_set_int("$sys_errno",sys_errno); + var_set_int("$errno",error); if (error != 0) { int i; if (command->abort_on_error) - die("command \"%.*s\" failed with error: %u my_errno: %d errno: %d", + { + report_or_die("command \"%.*s\" failed with error: %u my_errno: %d " + "errno: %d", command->first_word_len, command->query, error, my_errno, sys_errno); + DBUG_VOID_RETURN; + } i= match_expected_error(command, error, NULL); @@ -1163,20 +1301,25 @@ void handle_command_error(struct st_command *command, uint error, DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %u, errno: %d", command->first_word_len, command->query, error, sys_errno)); + revert_properties(); DBUG_VOID_RETURN; } if (command->expected_errors.count > 0) - die("command \"%.*s\" failed with wrong error: %u my_errno: %d errno: %d", - command->first_word_len, command->query, error, my_errno, sys_errno); + report_or_die("command \"%.*s\" failed with wrong error: %u " + "my_errno: %d errno: %d", + command->first_word_len, command->query, error, my_errno, + sys_errno); } else if (command->expected_errors.err[0].type == ERR_ERRNO && command->expected_errors.err[0].code.errnum != 0) { /* Error code we wanted was != 0, i.e. not an expected success */ - die("command \"%.*s\" succeeded - should have failed with errno %d...", + report_or_die("command \"%.*s\" succeeded - should have failed with " + "errno %d...", command->first_word_len, command->query, command->expected_errors.err[0].code.errnum); } + revert_properties(); DBUG_VOID_RETURN; } @@ -1186,6 +1329,9 @@ void close_connections() DBUG_ENTER("close_connections"); for (--next_con; next_con >= connections; --next_con) { +#ifdef EMBEDDED_LIBRARY + emb_close_connection(next_con); +#endif if (next_con->stmt) mysql_stmt_close(next_con->stmt); next_con->stmt= 0; @@ -1193,10 +1339,9 @@ void close_connections() next_con->mysql= 0; if (next_con->util_mysql) mysql_close(next_con->util_mysql); - my_free(next_con->name, MYF(MY_ALLOW_ZERO_PTR)); - free_embedded_data(next_con); + my_free(next_con->name); } - my_free(connections, MYF(MY_WME)); + my_free(connections); DBUG_VOID_RETURN; } @@ -1225,7 +1370,7 @@ void close_files() DBUG_PRINT("info", ("closing file: %s", cur_file->file_name)); fclose(cur_file->file); } - my_free((uchar*) cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); + my_free(cur_file->file_name); cur_file->file_name= 0; } DBUG_VOID_RETURN; @@ -1240,27 +1385,29 @@ void free_used_memory() if (connections) close_connections(); close_files(); - hash_free(&var_hash); + my_hash_free(&var_hash); for (i= 0 ; i < q_lines.elements ; i++) { struct st_command **q= dynamic_element(&q_lines, i, struct st_command**); - my_free((*q)->query_buf,MYF(MY_ALLOW_ZERO_PTR)); + my_free((*q)->query_buf); if ((*q)->content.str) dynstr_free(&(*q)->content); - my_free((*q),MYF(0)); + my_free((*q)); } for (i= 0; i < 10; i++) { if (var_reg[i].alloced_len) - my_free(var_reg[i].str_val, MYF(MY_WME)); + my_free(var_reg[i].str_val); } while (embedded_server_arg_count > 1) - my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); + my_free(embedded_server_args[--embedded_server_arg_count]); delete_dynamic(&q_lines); dynstr_free(&ds_res); + if (ds_warn) + dynstr_free(ds_warn); free_all_replace(); - my_free(opt_pass,MYF(MY_ALLOW_ZERO_PTR)); + my_free(opt_pass); free_defaults(default_argv); free_root(&require_file_root, MYF(0)); free_re(); @@ -1279,6 +1426,17 @@ static void cleanup_and_exit(int exit_code) /* Only call mysql_server_end if mysql_server_init has been called */ if (server_initialized) mysql_server_end(); + + /* + mysqltest is fundamentally written in a way that makes impossible + to free all memory before exit (consider memory allocated + for frame local DYNAMIC_STRING's and die() invoked down the stack. + + We close stderr here to stop unavoidable safemalloc reports + from polluting the output. + */ + fclose(stderr); + my_end(my_end_arg); if (!silent) { @@ -1298,52 +1456,63 @@ static void cleanup_and_exit(int exit_code) } } + sf_leaking_memory= 0; /* all memory should be freed by now */ exit(exit_code); } -void print_file_stack() +size_t print_file_stack(char *s, const char *end) { + char *start= s; struct st_test_file* err_file= cur_file; if (err_file == file_stack) - return; + return 0; for (;;) { err_file--; - fprintf(stderr, "included from %s at line %d:\n", - err_file->file_name, err_file->lineno); + s+= my_snprintf(s, end - s, "included from %s at line %d:\n", + err_file->file_name, err_file->lineno); if (err_file == file_stack) break; } + return s - start; } -void die(const char *fmt, ...) -{ - static int dying= 0; - va_list args; - DBUG_ENTER("die"); - DBUG_PRINT("enter", ("start_lineno: %d", start_lineno)); - fflush(stdout); - /* Print the error message */ - fprintf(stderr, "mysqltest: "); +static void make_error_message(char *buf, size_t len, const char *fmt, va_list args) +{ + char *s= buf, *end= buf + len; + s+= my_snprintf(s, end - s, "mysqltest: "); if (cur_file && cur_file != file_stack) { - fprintf(stderr, "In included file \"%s\": \n", - cur_file->file_name); - print_file_stack(); + s+= my_snprintf(s, end - s, "In included file \"%s\": \n", + cur_file->file_name); + s+= print_file_stack(s, end); } + if (start_lineno > 0) - fprintf(stderr, "At line %u: ", start_lineno); - if (fmt) - { - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - } - else - fprintf(stderr, "unknown error"); - fprintf(stderr, "\n"); + s+= my_snprintf(s, end -s, "At line %u: ", start_lineno); + if (!fmt) + fmt= "unknown error"; + + s+= my_vsnprintf(s, end - s, fmt, args); + s+= my_snprintf(s, end -s, "\n", start_lineno); +} + +void die(const char *fmt, ...) +{ + char buff[DIE_BUFF_SIZE]; + va_list args; + va_start(args, fmt); + make_error_message(buff, sizeof(buff), fmt, args); + really_die(buff); +} + +void really_die(const char *msg) +{ + static int dying= 0; + fflush(stdout); + fprintf(stderr, "%s", msg); fflush(stderr); /* @@ -1367,6 +1536,28 @@ void die(const char *fmt, ...) cleanup_and_exit(1); } +void report_or_die(const char *fmt, ...) +{ + va_list args; + DBUG_ENTER("report_or_die"); + + char buff[DIE_BUFF_SIZE]; + + va_start(args, fmt); + make_error_message(buff, sizeof(buff), fmt, args); + va_end(args); + + if (opt_continue_on_error) + { + /* Just log the error and continue */ + replace_dynstr_append(&ds_res, buff); + error_count++; + DBUG_VOID_RETURN; + } + + really_die(buff); +} + void abort_not_supported_test(const char *fmt, ...) { @@ -1379,7 +1570,10 @@ void abort_not_supported_test(const char *fmt, ...) file_stack->file_name); fprintf(stderr, "Detected in file %s at line %d\n", cur_file->file_name, cur_file->lineno); - print_file_stack(); + + char buff[DIE_BUFF_SIZE]; + print_file_stack(buff, buff + sizeof(buff)); + fprintf(stderr, "%s", buff); /* Print error message */ va_start(args, fmt); @@ -1511,7 +1705,10 @@ static int run_command(char* cmd, DBUG_PRINT("enter", ("cmd: %s", cmd)); if (!(res_file= popen(cmd, "r"))) - die("popen(\"%s\", \"r\") failed", cmd); + { + report_or_die("popen(\"%s\", \"r\") failed", cmd); + return -1; + } while (fgets(buf, sizeof(buf), res_file)) { @@ -1611,7 +1808,10 @@ static int diff_check(const char *diff_name) if (!(res_file= popen(buf, "r"))) die("popen(\"%s\", \"r\") failed", buf); - /* if diff is not present, nothing will be in stdout to increment have_diff */ + /* + if diff is not present, nothing will be in stdout to increment + have_diff + */ if (fgets(buf, sizeof(buf), res_file)) have_diff= 1; @@ -1924,7 +2124,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) void check_result() { - const char* mess= "Result content mismatch\n"; + const char *mess= 0; DBUG_ENTER("check_result"); DBUG_ASSERT(result_file_name); @@ -1932,9 +2132,13 @@ void check_result() switch (compare_files(log_file.file_name(), result_file_name)) { case RESULT_OK: - break; /* ok */ + if (!error_count) + break; /* ok */ + mess= "Got errors while running test"; + /* Fallthrough */ case RESULT_LENGTH_MISMATCH: - mess= "Result length mismatch\n"; + if (!mess) + mess= "Result length mismatch\n"; /* Fallthrough */ case RESULT_CONTENT_MISMATCH: { @@ -1944,6 +2148,10 @@ void check_result() */ char reject_file[FN_REFLEN]; size_t reject_length; + + if (!mess) + mess= "Result content mismatch\n"; + dirname_part(reject_file, result_file_name, &reject_length); if (access(reject_file, W_OK) == 0) @@ -2043,11 +2251,13 @@ static int strip_surrounding(char* str, char c1, char c2) static void strip_parentheses(struct st_command *command) { if (strip_surrounding(command->first_argument, '(', ')')) - die("%.*s - argument list started with '%c' must be ended with '%c'", - command->first_word_len, command->query, '(', ')'); + die("%.*s - argument list started with '%c' must be ended with '%c'", + command->first_word_len, command->query, '(', ')'); } +C_MODE_START + static uchar *get_var_key(const uchar* var, size_t *len, my_bool __attribute__((unused)) t) { @@ -2058,6 +2268,34 @@ static uchar *get_var_key(const uchar* var, size_t *len, } +static void var_free(void *v) +{ + VAR *var= (VAR*) v; + my_free(var->str_val); + if (var->alloced) + my_free(var); +} + +C_MODE_END + +void var_check_int(VAR *v) +{ + char *endptr; + char *str= v->str_val; + + /* Initially assume not a number */ + v->int_val= 0; + v->is_int= false; + v->int_dirty= false; + if (!str) return; + + v->int_val = (int) strtol(str, &endptr, 10); + /* It is an int if strtol consumed something up to end/space/tab */ + if (endptr > str && (!*endptr || *endptr == ' ' || *endptr == '\t')) + v->is_int= true; +} + + VAR *var_init(VAR *v, const char *name, int name_len, const char *val, int val_len) { @@ -2067,6 +2305,8 @@ VAR *var_init(VAR *v, const char *name, int name_len, const char *val, name_len = strlen(name); if (!val_len && val) val_len = strlen(val) ; + if (!val) + val_len= 0; val_alloc_len = val_len + 16; /* room to grow */ if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var) + name_len+2, MYF(MY_WME)))) @@ -2087,27 +2327,17 @@ VAR *var_init(VAR *v, const char *name, int name_len, const char *val, die("Out of memory"); if (val) - { memcpy(tmp_var->str_val, val, val_len); - tmp_var->str_val[val_len]= 0; - } + tmp_var->str_val[val_len]= 0; + + var_check_int(tmp_var); tmp_var->name_len = name_len; tmp_var->str_val_len = val_len; tmp_var->alloced_len = val_alloc_len; - tmp_var->int_val = (val) ? atoi(val) : 0; - tmp_var->int_dirty = 0; return tmp_var; } -void var_free(void *v) -{ - my_free(((VAR*) v)->str_val, MYF(MY_WME)); - if (((VAR*)v)->alloced) - my_free(v, MYF(MY_WME)); -} - - VAR* var_from_env(const char *name, const char *def_val) { const char *tmp; @@ -2149,8 +2379,8 @@ VAR* var_get(const char *var_name, const char **var_name_end, my_bool raw, if (length >= MAX_VAR_NAME_LENGTH) die("Too long variable name: %s", save_var_name); - if (!(v = (VAR*) hash_search(&var_hash, (const uchar*) save_var_name, - length))) + if (!(v = (VAR*) my_hash_search(&var_hash, (const uchar*) save_var_name, + length))) { char buff[MAX_VAR_NAME_LENGTH+1]; strmake(buff, save_var_name, length); @@ -2164,7 +2394,7 @@ VAR* var_get(const char *var_name, const char **var_name_end, my_bool raw, if (!raw && v->int_dirty) { sprintf(v->str_val, "%d", v->int_val); - v->int_dirty = 0; + v->int_dirty= false; v->str_val_len = strlen(v->str_val); } if (var_name_end) @@ -2181,7 +2411,7 @@ err: VAR *var_obtain(const char *name, int len) { VAR* v; - if ((v = (VAR*)hash_search(&var_hash, (const uchar *) name, len))) + if ((v = (VAR*)my_hash_search(&var_hash, (const uchar *) name, len))) return v; v = var_init(0, name, len, "", 0); my_hash_insert(&var_hash, (uchar*)v); @@ -2226,7 +2456,7 @@ void var_set(const char *var_name, const char *var_name_end, if (v->int_dirty) { sprintf(v->str_val, "%d", v->int_val); - v->int_dirty= 0; + v->int_dirty=false; v->str_val_len= strlen(v->str_val); } /* setenv() expects \0-terminated strings */ @@ -2259,6 +2489,51 @@ void var_set_int(const char* name, int value) void var_set_errno(int sql_errno) { var_set_int("$mysql_errno", sql_errno); + var_set_string("$mysql_errname", get_errname_from_code(sql_errno)); +} + +/* Functions to handle --disable and --enable properties */ + +void set_once_property(enum_prop prop, my_bool val) +{ + property &pr= prop_list[prop]; + pr.set= 1; + pr.old= *pr.var; + *pr.var= val; + var_set_int(pr.env_name, (val != pr.reverse)); + once_property= TRUE; +} + +void set_property(st_command *command, enum_prop prop, my_bool val) +{ + char* p= command->first_argument; + if (p && !strcmp (p, "ONCE")) + { + command->last_argument= p + 4; + set_once_property(prop, val); + return; + } + property &pr= prop_list[prop]; + *pr.var= val; + pr.set= 0; + var_set_int(pr.env_name, (val != pr.reverse)); +} + +void revert_properties() +{ + if (! once_property) + return; + for (int i= 0; i < (int) P_MAX; i++) + { + property &pr= prop_list[i]; + if (pr.set) + { + *pr.var= pr.old; + pr.set= 0; + var_set_int(pr.env_name, (pr.old != pr.reverse)); + } + } + once_property=FALSE; } @@ -2327,8 +2602,8 @@ void var_query_set(VAR *var, const char *query, const char** query_end) if (mysql_real_query(mysql, ds_query.str, ds_query.length)) { - handle_error (curr_command, mysql_errno(mysql), mysql_error(mysql), - mysql_sqlstate(mysql), &ds_res); + handle_error(curr_command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), &ds_res); /* If error was acceptable, return empty string */ dynstr_free(&ds_query); eval_expr(var, "", 0); @@ -2336,7 +2611,12 @@ void var_query_set(VAR *var, const char *query, const char** query_end) } if (!(res= mysql_store_result(mysql))) - die("Query '%s' didn't return a result set", ds_query.str); + { + report_or_die("Query '%s' didn't return a result set", ds_query.str); + dynstr_free(&ds_query); + eval_expr(var, "", 0); + return; + } dynstr_free(&ds_query); if ((row= mysql_fetch_row(res)) && row[0]) @@ -2356,13 +2636,29 @@ void var_query_set(VAR *var, const char *query, const char** query_end) if (row[i]) { /* Add column to tab separated string */ - dynstr_append_mem(&result, row[i], lengths[i]); + char *val= row[i]; + int len= lengths[i]; + + if (glob_replace_regex) + { + /* Regex replace */ + if (!multi_reg_replace(glob_replace_regex, (char*)val)) + { + val= glob_replace_regex->buf; + len= strlen(val); + } + } + + if (glob_replace) + replace_strings_append(glob_replace, &result, val, len); + else + dynstr_append_mem(&result, val, len); } dynstr_append_mem(&result, "\t", 1); } end= result.str + result.length-1; /* Evaluation should not recurse via backtick */ - eval_expr(var, result.str, (const char**) &end, false); + eval_expr(var, result.str, (const char**) &end, false, false); dynstr_free(&result); } else @@ -2373,6 +2669,59 @@ void var_query_set(VAR *var, const char *query, const char** query_end) } +static void +set_result_format_version(ulong new_version) +{ + switch (new_version){ + case 1: + /* The first format */ + break; + case 2: + /* New format that also writes comments and empty lines + from test file to result */ + break; + default: + die("Version format %lu has not yet been implemented", new_version); + break; + } + opt_result_format_version= new_version; +} + + +/* + Set the result format version to use when generating + the .result file +*/ + +static void +do_result_format_version(struct st_command *command) +{ + long version; + static DYNAMIC_STRING ds_version; + const struct command_arg result_format_args[] = { + {"version", ARG_STRING, TRUE, &ds_version, "Version to use"} + }; + + DBUG_ENTER("do_result_format_version"); + + check_command_args(command, command->first_argument, + result_format_args, + sizeof(result_format_args)/sizeof(struct command_arg), + ','); + + /* Convert version number to int */ + if (!str2int(ds_version.str, 10, (long) 0, (long) INT_MAX, &version)) + die("Invalid version number: '%s'", ds_version.str); + + set_result_format_version(version); + + dynstr_append(&ds_res, "result_format: "); + dynstr_append_mem(&ds_res, ds_version.str, ds_version.length); + dynstr_append(&ds_res, "\n"); + dynstr_free(&ds_version); +} + + /* Set variable from the result of a field in a query @@ -2442,16 +2791,23 @@ void var_set_query_get_value(struct st_command *command, VAR *var) /* Run the query */ if (mysql_real_query(mysql, ds_query.str, ds_query.length)) { - handle_error (curr_command, mysql_errno(mysql), mysql_error(mysql), - mysql_sqlstate(mysql), &ds_res); + handle_error(curr_command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), &ds_res); /* If error was acceptable, return empty string */ dynstr_free(&ds_query); + dynstr_free(&ds_col); eval_expr(var, "", 0); DBUG_VOID_RETURN; } if (!(res= mysql_store_result(mysql))) - die("Query '%s' didn't return a result set", ds_query.str); + { + report_or_die("Query '%s' didn't return a result set", ds_query.str); + dynstr_free(&ds_query); + dynstr_free(&ds_col); + eval_expr(var, "", 0); + return; + } { /* Find column number from the given column name */ @@ -2471,8 +2827,11 @@ void var_set_query_get_value(struct st_command *command, VAR *var) if (col_no == -1) { mysql_free_result(res); - die("Could not find column '%s' in the result of '%s'", - ds_col.str, ds_query.str); + report_or_die("Could not find column '%s' in the result of '%s'", + ds_col.str, ds_query.str); + dynstr_free(&ds_query); + dynstr_free(&ds_col); + return; } DBUG_PRINT("info", ("Found column %d with name '%s'", i, fields[i].name)); @@ -2501,7 +2860,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var) break; } } - eval_expr(var, value, 0, false); + eval_expr(var, value, 0, false, false); } dynstr_free(&ds_query); mysql_free_result(res); @@ -2513,6 +2872,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var) void var_copy(VAR *dest, VAR *src) { dest->int_val= src->int_val; + dest->is_int= src->is_int; dest->int_dirty= src->int_dirty; /* Alloc/realloc data for str_val in dest */ @@ -2531,7 +2891,8 @@ void var_copy(VAR *dest, VAR *src) } -void eval_expr(VAR *v, const char *p, const char **p_end, bool do_eval) +void eval_expr(VAR *v, const char *p, const char **p_end, + bool open_end, bool do_eval) { DBUG_ENTER("eval_expr"); @@ -2553,7 +2914,7 @@ void eval_expr(VAR *v, const char *p, const char **p_end, bool do_eval) /* Make sure there was just a $variable and nothing else */ const char* end= *p_end + 1; - if (end < expected_end) + if (end < expected_end && !open_end) die("Found junk '%.*s' after $variable in expression", (int)(expected_end - end - 1), end); @@ -2602,48 +2963,134 @@ void eval_expr(VAR *v, const char *p, const char **p_end, bool do_eval) v->str_val_len = new_val_len; memcpy(v->str_val, p, new_val_len); v->str_val[new_val_len] = 0; - v->int_val=atoi(p); - DBUG_PRINT("info", ("atoi on '%s', returns: %d", p, v->int_val)); - v->int_dirty=0; + var_check_int(v); } DBUG_VOID_RETURN; } -int open_file(const char *name) +bool open_and_set_current(const char *name) +{ + FILE *opened= fopen(name, "rb"); + + if (!opened) + return false; + + cur_file++; + cur_file->file= opened; + cur_file->file_name= my_strdup(name, MYF(MY_FAE)); + cur_file->lineno=1; + return true; +} + + +void open_file(const char *name) { char buff[FN_REFLEN]; size_t length; + const char *curname= cur_file->file_name; DBUG_ENTER("open_file"); DBUG_PRINT("enter", ("name: %s", name)); - /* Extract path from current file and try it as base first */ - if (dirname_part(buff, cur_file->file_name, &length)) + if (cur_file == file_stack_end) + die("Source directives are nesting too deep"); + + if (test_if_hard_path(name)) { - strxmov(buff, buff, name, NullS); - if (access(buff, F_OK) == 0){ - DBUG_PRINT("info", ("The file exists")); - name= buff; - } + if (open_and_set_current(name)) + DBUG_VOID_RETURN; } - if (!test_if_hard_path(name)) + else { - strxmov(buff, opt_basedir, name, NullS); - name=buff; - } - fn_format(buff, name, "", "", MY_UNPACK_FILENAME); + /* + if overlay-dir is specified, and the file is located somewhere + under overlay-dir or under suite-dir, the search works as follows: + + 0.let suffix be current file dirname relative to siute-dir or overlay-dir + 1.try in overlay-dir/suffix + 2.try in suite-dir/suffix + 3.try in overlay-dir + 4.try in suite-dir + 5.try in basedir + + consider an example: 'rty' overlay of the 'qwe' suite, + file qwe/include/some.inc contains the line + --source thing.inc + we look for it in this order: + 0.suffix is "include/" + 1.try in rty/include/thing.inc + 2.try in qwe/include/thing.inc + 3.try in try/thing.inc | this is useful when t/a.test has + 4.try in qwe/thing.inc | source include/b.inc; + 5.try in mysql-test/include/thing.inc + + otherwise the search is as follows + 1.try in current file dirname + 3.try in overlay-dir (if any) + 4.try in suite-dir + 5.try in basedir + */ - if (cur_file == file_stack_end) - die("Source directives are nesting too deep"); - cur_file++; - if (!(cur_file->file = fopen(buff, "rb"))) - { - cur_file--; - die("Could not open '%s' for reading, errno: %d", buff, errno); + bool in_overlay= opt_overlay_dir && + !strncmp(curname, opt_overlay_dir, overlay_dir_len); + bool in_suiteir= opt_overlay_dir && !in_overlay && + !strncmp(curname, opt_suite_dir, suite_dir_len); + if (in_overlay || in_suiteir) + { + size_t prefix_len = in_overlay ? overlay_dir_len : suite_dir_len; + char buf2[FN_REFLEN], *suffix= buf2 + prefix_len; + dirname_part(buf2, curname, &length); + + /* 1. first we look in the overlay dir */ + strxnmov(buff, sizeof(buff), opt_overlay_dir, suffix, name, NullS); + + /* + Overlayed rty/include/thing.inc can contain the line + --source thing.inc + which would mean to include qwe/include/thing.inc. + But it looks like including "itself", so don't try to open the file, + if buff contains the same file name as curname. + */ + if (strcmp(buff, curname) && open_and_set_current(buff)) + DBUG_VOID_RETURN; + + /* 2. if that failed, we look in the suite dir */ + strxnmov(buff, sizeof(buff), opt_suite_dir, suffix, name, NullS); + + /* buff can not be equal to curname, as a file can never include itself */ + if (open_and_set_current(buff)) + DBUG_VOID_RETURN; + } + else + { + /* 1. try in current file dirname */ + dirname_part(buff, curname, &length); + strxnmov(buff, sizeof(buff), buff, name, NullS); + if (open_and_set_current(buff)) + DBUG_VOID_RETURN; + } + + /* 3. now, look in the overlay dir */ + if (opt_overlay_dir) + { + strxmov(buff, opt_overlay_dir, name, NullS); + if (open_and_set_current(buff)) + DBUG_VOID_RETURN; + } + + /* 4. if that failed - look in the suite dir */ + strxmov(buff, opt_suite_dir, name, NullS); + if (open_and_set_current(buff)) + DBUG_VOID_RETURN; + + /* 5. the last resort - look in the base dir */ + strxnmov(buff, sizeof(buff), opt_basedir, name, NullS); + if (open_and_set_current(buff)) + DBUG_VOID_RETURN; } - cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); - cur_file->lineno=1; - DBUG_RETURN(0); + + die("Could not open '%s' for reading, errno: %d", name, errno); + DBUG_VOID_RETURN; } @@ -2824,7 +3271,10 @@ void do_exec(struct st_command *command) while (*cmd && my_isspace(charset_info, *cmd)) cmd++; if (!*cmd) - die("Missing argument in exec"); + { + report_or_die("Missing argument in exec"); + return; + } command->last_argument= command->end; init_dynamic_string(&ds_cmd, 0, command->query_len+256, 256); @@ -2856,10 +3306,12 @@ void do_exec(struct st_command *command) DBUG_PRINT("info", ("Executing '%s' as '%s'", command->first_argument, ds_cmd.str)); - if (!(res_file= my_popen(&ds_cmd, "r")) && command->abort_on_error) + if (!(res_file= my_popen(&ds_cmd, "r"))) { dynstr_free(&ds_cmd); - die("popen(\"%s\", \"r\") failed", command->first_argument); + if (command->abort_on_error) + report_or_die("popen(\"%s\", \"r\") failed", command->first_argument); + return; } ds_result= &ds_res; @@ -2896,11 +3348,12 @@ void do_exec(struct st_command *command) if (command->abort_on_error) { - log_msg("exec of '%s' failed, error: %d, status: %d, errno: %d", - ds_cmd.str, error, status, errno); + report_or_die("exec of '%s' failed, error: %d, status: %d, errno: %d\n" + "Output from before failure:\n%s\n", + ds_cmd.str, error, status, errno, + ds_res.str); dynstr_free(&ds_cmd); - die("command \"%s\" failed\n\nOutput from before failure:\n%s\n", - command->first_argument, ds_res.str); + return; } DBUG_PRINT("info", @@ -2915,8 +3368,8 @@ void do_exec(struct st_command *command) { dynstr_free(&ds_cmd); if (command->expected_errors.count > 0) - die("command \"%s\" failed with wrong error: %d", - command->first_argument, status); + report_or_die("command \"%s\" failed with wrong error: %d", + command->first_argument, status); } } else if (command->expected_errors.err[0].type == ERR_ERRNO && @@ -2926,8 +3379,10 @@ void do_exec(struct st_command *command) log_msg("exec of '%s failed, error: %d, errno: %d", ds_cmd.str, error, errno); dynstr_free(&ds_cmd); - die("command \"%s\" succeeded - should have failed with errno %d...", - command->first_argument, command->expected_errors.err[0].code.errnum); + report_or_die("command \"%s\" succeeded - should have failed with " + "errno %d...", + command->first_argument, + command->expected_errors.err[0].code.errnum); } dynstr_free(&ds_cmd); @@ -2961,11 +3416,14 @@ int do_modify_var(struct st_command *command, const char *p= command->first_argument; VAR* v; if (!*p) - die("Missing argument to %.*s", command->first_word_len, command->query); + die("Missing argument to %.*s", command->first_word_len, + command->query); if (*p != '$') die("The argument to %.*s must be a variable (start with $)", command->first_word_len, command->query); v= var_get(p, &p, 1, 0); + if (! v->is_int) + die("Cannot perform inc/dec on a non-numeric value"); switch (op) { case DO_DEC: v->int_val--; @@ -2977,7 +3435,7 @@ int do_modify_var(struct st_command *command, die("Invalid operator to do_modify_var"); break; } - v->int_dirty= 1; + v->int_dirty= true; command->last_argument= (char*)++p; return 0; } @@ -3025,7 +3483,10 @@ void do_system(struct st_command *command) DBUG_ENTER("do_system"); if (strlen(command->first_argument) == 0) - die("Missing arguments to system, nothing to do!"); + { + report_or_die("Missing arguments to system, nothing to do!"); + return; + } init_dynamic_string(&ds_cmd, 0, command->query_len + 64, 256); @@ -3046,12 +3507,14 @@ void do_system(struct st_command *command) if (my_system(&ds_cmd)) { if (command->abort_on_error) - die("system command '%s' failed", command->first_argument); - - /* If ! abort_on_error, log message and continue */ - dynstr_append(&ds_res, "system command '"); - replace_dynstr_append(&ds_res, command->first_argument); - dynstr_append(&ds_res, "' failed\n"); + report_or_die("system command '%s' failed", command->first_argument); + else + { + /* If ! abort_on_error, log message and continue */ + dynstr_append(&ds_res, "system command '"); + replace_dynstr_append(&ds_res, command->first_argument); + dynstr_append(&ds_res, "' failed\n"); + } } command->last_argument= command->end; @@ -3237,8 +3700,9 @@ void do_copy_file(struct st_command *command) ' '); DBUG_PRINT("info", ("Copy %s to %s", ds_from_file.str, ds_to_file.str)); + /* MY_HOLD_ORIGINAL_MODES prevents attempts to chown the file */ error= (my_copy(ds_from_file.str, ds_to_file.str, - MYF(MY_DONT_OVERWRITE_FILE | MY_WME)) != 0); + MYF(MY_DONT_OVERWRITE_FILE | MY_WME | MY_HOLD_ORIGINAL_MODES)) != 0); handle_command_error(command, error, my_errno); dynstr_free(&ds_from_file); dynstr_free(&ds_to_file); @@ -3295,8 +3759,8 @@ void do_move_file(struct st_command *command) void do_chmod_file(struct st_command *command) { - int error; long mode= 0; + int err_code; static DYNAMIC_STRING ds_mode; static DYNAMIC_STRING ds_file; const struct command_arg chmod_file_args[] = { @@ -3316,10 +3780,10 @@ void do_chmod_file(struct st_command *command) die("You must write a 4 digit octal number for mode"); DBUG_PRINT("info", ("chmod %o %s", (uint)mode, ds_file.str)); - error= 0; - if (chmod(ds_file.str, mode)) - error= 1; - handle_command_error(command, error, errno); + err_code= chmod(ds_file.str, mode); + if (err_code < 0) + err_code= 1; + handle_command_error(command, err_code, errno); dynstr_free(&ds_mode); dynstr_free(&ds_file); DBUG_VOID_RETURN; @@ -3597,12 +4061,12 @@ void read_until_delimiter(DYNAMIC_STRING *ds, No characters except \n are allowed on the same line as the command */ - die("Trailing characters found after command"); + report_or_die("Trailing characters found after command"); } if (feof(cur_file->file)) - die("End of file encountered before '%s' delimiter was found", - ds_delimiter->str); + report_or_die("End of file encountered before '%s' delimiter was found", + ds_delimiter->str); if (match_delimiter(c, ds_delimiter->str, ds_delimiter->length)) { @@ -4006,8 +4470,13 @@ void do_perl(struct st_command *command) /* Format the "perl <filename>" command */ my_snprintf(buf, sizeof(buf), "perl %s", temp_file_path); - if (!(res_file= popen(buf, "r")) && command->abort_on_error) - die("popen(\"%s\", \"r\") failed", buf); + if (!(res_file= popen(buf, "r"))) + { + if (command->abort_on_error) + die("popen(\"%s\", \"r\") failed", buf); + dynstr_free(&ds_delimiter); + return; + } while (fgets(buf, sizeof(buf), res_file)) { @@ -4038,7 +4507,7 @@ void do_perl(struct st_command *command) abort_not_supported_test("perl not found in path"); #endif else - handle_command_error(command, WEXITSTATUS(error), my_errno); + handle_command_error(command, exstat, my_errno); } dynstr_free(&ds_delimiter); DBUG_VOID_RETURN; @@ -4162,14 +4631,14 @@ void do_sync_with_master2(struct st_command *command, long offset) information is not initialized, the arguments are incorrect, or an error has occured */ - die("%.*s failed: '%s' returned NULL "\ + die("%.*s failed: '%s' returned NULL " \ "indicating slave SQL thread failure", command->first_word_len, command->query, query_buf); } if (result == -1) - die("%.*s failed: '%s' returned -1 "\ + die("%.*s failed: '%s' returned -1 " \ "indicating timeout after %d seconds", command->first_word_len, command->query, query_buf, timeout); else @@ -4209,12 +4678,8 @@ int do_save_master_pos() MYSQL_ROW row; MYSQL *mysql = cur_con->mysql; const char *query; - int rpl_parse; DBUG_ENTER("do_save_master_pos"); - rpl_parse = mysql_rpl_parse_enabled(mysql); - mysql_disable_rpl_parse(mysql); - #ifdef HAVE_NDB_BINLOG /* Wait for ndb binlog to be up-to-date with all changes @@ -4255,7 +4720,7 @@ int do_save_master_pos() const char latest_applied_binlog_epoch_str[]= "latest_applied_binlog_epoch="; if (count) - sleep(1); + my_sleep(100*1000); /* 100ms */ if (mysql_query(mysql, query= "show engine ndb status")) die("failed in '%s': %d %s", query, mysql_errno(mysql), mysql_error(mysql)); @@ -4344,7 +4809,7 @@ int do_save_master_pos() count++; if (latest_handled_binlog_epoch >= start_epoch) do_continue= 0; - else if (count > 30) + else if (count > 300) /* 30s */ { break; } @@ -4364,10 +4829,6 @@ int do_save_master_pos() strnmov(master_pos.file, row[0], sizeof(master_pos.file)-1); master_pos.pos = strtoul(row[1], (char**) 0, 10); mysql_free_result(res); - - if (rpl_parse) - mysql_enable_rpl_parse(mysql); - DBUG_RETURN(0); } @@ -4426,33 +4887,11 @@ void do_let(struct st_command *command) var_set(var_name, var_name_end, let_rhs_expr.str, (let_rhs_expr.str + let_rhs_expr.length)); dynstr_free(&let_rhs_expr); + revert_properties(); DBUG_VOID_RETURN; } -int do_rpl_probe(struct st_command *command __attribute__((unused))) -{ - DBUG_ENTER("do_rpl_probe"); - if (mysql_rpl_probe(cur_con->mysql)) - die("Failed in mysql_rpl_probe(): '%s'", mysql_error(cur_con->mysql)); - DBUG_RETURN(0); -} - - -int do_enable_rpl_parse(struct st_command *command __attribute__((unused))) -{ - mysql_enable_rpl_parse(cur_con->mysql); - return 0; -} - - -int do_disable_rpl_parse(struct st_command *command __attribute__((unused))) -{ - mysql_disable_rpl_parse(cur_con->mysql); - return 0; -} - - /* Sleep the number of specified seconds @@ -4494,7 +4933,8 @@ int do_sleep(struct st_command *command, my_bool real_sleep) while (my_isspace(charset_info, *p)) p++; if (!*p) - die("Missing argument to %.*s", command->first_word_len, command->query); + die("Missing argument to %.*s", command->first_word_len, + command->query); sleep_start= p; /* Check that arg starts with a digit, not handled by my_strtod */ if (!my_isdigit(charset_info, *sleep_start)) @@ -4566,16 +5006,21 @@ int query_get_string(MYSQL* mysql, const char* query, MYSQL_ROW row; if (mysql_query(mysql, query)) - die("'%s' failed: %d %s", query, - mysql_errno(mysql), mysql_error(mysql)); + { + report_or_die("'%s' failed: %d %s", query, + mysql_errno(mysql), mysql_error(mysql)); + return 1; + } if ((res= mysql_store_result(mysql)) == NULL) - die("Failed to store result: %d %s", - mysql_errno(mysql), mysql_error(mysql)); + { + report_or_die("Failed to store result: %d %s", + mysql_errno(mysql), mysql_error(mysql)); + return 1; + } if ((row= mysql_fetch_row(res)) == NULL) { mysql_free_result(res); - ds= 0; return 1; } init_dynamic_string(ds, (row[column] ? row[column] : "NULL"), ~0, 32); @@ -4695,18 +5140,19 @@ void do_shutdown_server(struct st_command *command) } -#if MYSQL_VERSION_ID >= 50000 -/* List of error names to error codes, available from 5.0 */ +/* List of error names to error codes */ typedef struct { const char *name; uint code; + const char *text; } st_error; static st_error global_error_names[] = { + { "<No error>", -1U, "" }, #include <mysqld_ername.h> - { 0, 0 } + { 0, 0, 0 } }; uint get_errcode_from_name(char *error_name, char *error_end) @@ -4735,28 +5181,58 @@ uint get_errcode_from_name(char *error_name, char *error_end) die("Unknown SQL error name '%s'", error_name); DBUG_RETURN(0); } -#else -uint get_errcode_from_name(char *error_name __attribute__((unused)), - char *error_end __attribute__((unused))) + +const char *get_errname_from_code (uint error_code) { - abort_not_in_this_version(); - return 0; /* Never reached */ -} -#endif + st_error *e= global_error_names; + DBUG_ENTER("get_errname_from_code"); + DBUG_PRINT("enter", ("error_code: %d", error_code)); + if (! error_code) + { + DBUG_RETURN(""); + } + for (; e->name; e++) + { + if (e->code == error_code) + { + DBUG_RETURN(e->name); + } + } + /* Apparently, errors without known names may occur */ + DBUG_RETURN("<Unknown>"); +} void do_get_errcodes(struct st_command *command) { struct st_match_err *to= saved_expected_errors.err; - char *p= command->first_argument; - uint count= 0; - DBUG_ENTER("do_get_errcodes"); - if (!*p) + if (!*command->first_argument) die("Missing argument(s) to 'error'"); + /* TODO: Potentially, there is a possibility of variables + being expanded twice, e.g. + + let $errcodes = 1,\$a; + let $a = 1051; + error $errcodes; + DROP TABLE unknown_table; + ... + Got one of the listed errors + + But since it requires manual escaping, it does not seem + particularly dangerous or error-prone. + */ + DYNAMIC_STRING ds; + init_dynamic_string(&ds, 0, command->query_len + 64, 256); + do_eval(&ds, command->first_argument, command->end, !is_windows); + char *p= ds.str; + + uint count= 0; + char *next; + do { char *end; @@ -4770,6 +5246,17 @@ void do_get_errcodes(struct st_command *command) while (*end && *end != ',' && *end != ' ') end++; + next=end; + + /* code to handle variables passed to mysqltest */ + if( *p == '$') + { + const char* fin; + VAR *var = var_get(p,&fin,0,0); + p=var->str_val; + end=p+var->str_val_len; + } + if (*p == 'S') { char *to_ptr= to->code.sqlstate; @@ -4822,7 +5309,7 @@ void do_get_errcodes(struct st_command *command) while (*p && p != end) { if (!my_isdigit(charset_info, *p)) - die("Invalid argument to error: '%s' - "\ + die("Invalid argument to error: '%s' - " \ "the errno may only consist of digits[0-9]", command->first_argument); p++; @@ -4844,7 +5331,7 @@ void do_get_errcodes(struct st_command *command) die("Too many errorcodes specified"); /* Set pointer to the end of the last error code */ - p= end; + p= next; /* Find next ',' */ while (*p && *p != ',') @@ -4855,11 +5342,15 @@ void do_get_errcodes(struct st_command *command) } while (*p); - command->last_argument= p; + command->last_argument= command->first_argument; + while (*command->last_argument) + command->last_argument++; + to->type= ERR_EMPTY; /* End of data */ DBUG_PRINT("info", ("Expected errors: %d", count)); saved_expected_errors.count= count; + dynstr_free(&ds); DBUG_VOID_RETURN; } @@ -5052,7 +5543,7 @@ void do_close_connection(struct st_command *command) we need to check if the query's thread was finished and probably wait (embedded-server specific) */ - wait_query_thread_end(con); + emb_close_connection(con); #endif /*EMBEDDED_LIBRARY*/ if (con->stmt) mysql_stmt_close(con->stmt); @@ -5060,14 +5551,13 @@ void do_close_connection(struct st_command *command) mysql_close(con->mysql); con->mysql= 0; - free_embedded_data(con); if (con->util_mysql) mysql_close(con->util_mysql); con->util_mysql= 0; con->pending= FALSE; - my_free(con->name, MYF(MY_ALLOW_ZERO_PTR)); + my_free(con->name); /* When the connection is closed set name to "-closed_connection-" @@ -5278,6 +5768,7 @@ do_handle_error: var_set_errno(0); handle_no_error(command); + revert_properties(); return 1; /* Connected */ } @@ -5326,6 +5817,7 @@ void do_connect(struct st_command *command) static DYNAMIC_STRING ds_port; static DYNAMIC_STRING ds_sock; static DYNAMIC_STRING ds_options; + static DYNAMIC_STRING ds_default_auth; #ifdef HAVE_SMEM static DYNAMIC_STRING ds_shm; #endif @@ -5337,7 +5829,8 @@ void do_connect(struct st_command *command) { "database", ARG_STRING, FALSE, &ds_database, "Database to select after connect" }, { "port", ARG_STRING, FALSE, &ds_port, "Port to connect to" }, { "socket", ARG_STRING, FALSE, &ds_sock, "Socket to connect with" }, - { "options", ARG_STRING, FALSE, &ds_options, "Options to use while connecting" } + { "options", ARG_STRING, FALSE, &ds_options, "Options to use while connecting" }, + { "default_auth", ARG_STRING, FALSE, &ds_default_auth, "Default authentication to use" } }; DBUG_ENTER("do_connect"); @@ -5422,16 +5915,20 @@ void do_connect(struct st_command *command) if (!(con_slot= find_connection_by_name("-closed_connection-"))) die("Connection limit exhausted, you can have max %d connections", opt_max_connections); - my_free(con_slot->name, MYF(0)); + my_free(con_slot->name); con_slot->name= 0; } -#ifdef EMBEDDED_LIBRARY - con_slot->query_done= 1; - con_slot->has_thread= FALSE; -#endif + init_connection_thd(con_slot); + if (!(con_slot->mysql= mysql_init(0))) die("Failed on mysql_init()"); + + if (opt_connect_timeout) + mysql_options(con_slot->mysql, MYSQL_OPT_CONNECT_TIMEOUT, + (void *) &opt_connect_timeout); + + mysql_options(con_slot->mysql, MYSQL_OPT_NONBLOCK, 0); if (opt_compress || con_compress) mysql_options(con_slot->mysql, MYSQL_OPT_COMPRESS, NullS); mysql_options(con_slot->mysql, MYSQL_OPT_LOCAL_INFILE, 0); @@ -5440,18 +5937,14 @@ void do_connect(struct st_command *command) if (opt_charsets_dir) mysql_options(con_slot->mysql, MYSQL_SET_CHARSET_DIR, opt_charsets_dir); - if (opt_connect_timeout >= 0) - mysql_options(con_slot->mysql, MYSQL_OPT_CONNECT_TIMEOUT, - &opt_connect_timeout); - -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) if (opt_use_ssl) con_ssl= 1; #endif if (con_ssl) { -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) mysql_ssl_set(con_slot->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); #if MYSQL_VERSION_ID >= 50000 @@ -5493,6 +5986,12 @@ void do_connect(struct st_command *command) if (ds_database.length == 0) dynstr_set(&ds_database, opt_db); + if (opt_plugin_dir && *opt_plugin_dir) + mysql_options(con_slot->mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir); + + if (ds_default_auth.length) + mysql_options(con_slot->mysql, MYSQL_DEFAULT_AUTH, ds_default_auth.str); + /* Special database to allow one to connect without a database name */ if (ds_database.length && !strcmp(ds_database.str,"*NO-ONE*")) dynstr_set(&ds_database, ""); @@ -5521,6 +6020,7 @@ void do_connect(struct st_command *command) dynstr_free(&ds_port); dynstr_free(&ds_sock); dynstr_free(&ds_options); + dynstr_free(&ds_default_auth); #ifdef HAVE_SMEM dynstr_free(&ds_shm); #endif @@ -5560,6 +6060,40 @@ int do_done(struct st_command *command) return 0; } +/* Operands available in if or while conditions */ + +enum block_op { + EQ_OP, + NE_OP, + GT_OP, + GE_OP, + LT_OP, + LE_OP, + ILLEG_OP +}; + + +enum block_op find_operand(const char *start) +{ + char first= *start; + char next= *(start+1); + + if (first == '=' && next == '=') + return EQ_OP; + if (first == '!' && next == '=') + return NE_OP; + if (first == '>' && next == '=') + return GE_OP; + if (first == '>') + return GT_OP; + if (first == '<' && next == '=') + return LE_OP; + if (first == '<') + return LT_OP; + + return ILLEG_OP; +} + /* Process start of a "if" or "while" statement @@ -5585,6 +6119,13 @@ int do_done(struct st_command *command) A '!' can be used before the <expr> to indicate it should be executed if it evaluates to zero. + <expr> can also be a simple comparison condition: + + <variable> <op> <expr> + + The left hand side must be a variable, the right hand side can be a + variable, number, string or `query`. Operands are ==, !=, <, <=, >, >=. + == and != can be used for strings, all can be used for numerical values. */ void do_block(enum block_cmd cmd, struct st_command* command) @@ -5620,6 +6161,9 @@ void do_block(enum block_cmd cmd, struct st_command* command) if (!expr_start++) die("missing '(' in %s", cmd_name); + while (my_isspace(charset_info, *expr_start)) + expr_start++; + /* Check for !<expr> */ if (*expr_start == '!') { @@ -5640,14 +6184,110 @@ void do_block(enum block_cmd cmd, struct st_command* command) die("Missing '{' after %s. Found \"%s\"", cmd_name, p); var_init(&v,0,0,0,0); - eval_expr(&v, expr_start, &expr_end); + /* If expression starts with a variable, it may be a compare condition */ + + if (*expr_start == '$') + { + const char *curr_ptr= expr_end; + eval_expr(&v, expr_start, &curr_ptr, true); + while (my_isspace(charset_info, *++curr_ptr)) + {} + /* If there was nothing past the variable, skip condition part */ + if (curr_ptr == expr_end) + goto NO_COMPARE; + + enum block_op operand= find_operand(curr_ptr); + if (operand == ILLEG_OP) + die("Found junk '%.*s' after $variable in condition", + (int)(expr_end - curr_ptr), curr_ptr); + + /* We could silently allow this, but may be confusing */ + if (not_expr) + die("Negation and comparison should not be combined, please rewrite"); + + /* Skip the 1 or 2 chars of the operand, then white space */ + if (operand == LT_OP || operand == GT_OP) + { + curr_ptr++; + } + else + { + curr_ptr+= 2; + } + while (my_isspace(charset_info, *curr_ptr)) + curr_ptr++; + if (curr_ptr == expr_end) + die("Missing right operand in comparison"); + + /* Strip off trailing white space */ + while (my_isspace(charset_info, expr_end[-1])) + expr_end--; + /* strip off ' or " around the string */ + if (*curr_ptr == '\'' || *curr_ptr == '"') + { + if (expr_end[-1] != *curr_ptr) + die("Unterminated string value"); + curr_ptr++; + expr_end--; + } + VAR v2; + var_init(&v2,0,0,0,0); + eval_expr(&v2, curr_ptr, &expr_end); + + if ((operand!=EQ_OP && operand!=NE_OP) && ! (v.is_int && v2.is_int)) + die("Only == and != are supported for string values"); + + /* Now we overwrite the first variable with 0 or 1 (for false or true) */ + + switch (operand) + { + case EQ_OP: + if (v.is_int) + v.int_val= (v2.is_int && v2.int_val == v.int_val); + else + v.int_val= !strcmp (v.str_val, v2.str_val); + break; + + case NE_OP: + if (v.is_int) + v.int_val= ! (v2.is_int && v2.int_val == v.int_val); + else + v.int_val= (strcmp (v.str_val, v2.str_val) != 0); + break; + + case LT_OP: + v.int_val= (v.int_val < v2.int_val); + break; + case LE_OP: + v.int_val= (v.int_val <= v2.int_val); + break; + case GT_OP: + v.int_val= (v.int_val > v2.int_val); + break; + case GE_OP: + v.int_val= (v.int_val >= v2.int_val); + break; + case ILLEG_OP: + die("Impossible operator, this cannot happen"); + } + + v.is_int= TRUE; + var_free(&v2); + } else + { + if (*expr_start != '`' && ! my_isdigit(charset_info, *expr_start)) + die("Expression in if/while must beging with $, ` or a number"); + eval_expr(&v, expr_start, &expr_end); + } + + NO_COMPARE: /* Define inner block */ cur_block++; cur_block->cmd= cmd; - if (v.int_val) + if (v.is_int) { - cur_block->ok= TRUE; + cur_block->ok= (v.int_val != 0); } else /* Any non-empty string which does not begin with 0 is also TRUE */ { @@ -5755,7 +6395,7 @@ my_bool end_of_query(int c) int read_line(char *buf, int size) { - char c, UNINIT_VAR(last_quote); + char c, UNINIT_VAR(last_quote), last_char= 0; char *p= buf, *buf_end= buf + size - 1; int skip_char= 0; my_bool have_slash= FALSE; @@ -5778,7 +6418,7 @@ int read_line(char *buf, int size) fclose(cur_file->file); cur_file->file= 0; } - my_free((uchar*) cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); + my_free(cur_file->file_name); cur_file->file_name= 0; if (cur_file == file_stack) { @@ -5859,14 +6499,24 @@ int read_line(char *buf, int size) } else if (my_isspace(charset_info, c)) { - /* Skip all space at begining of line */ if (c == '\n') { + if (last_char == '\n') + { + /* Two new lines in a row, return empty line */ + DBUG_PRINT("info", ("Found two new lines in a row")); + *p++= c; + *p= 0; + DBUG_RETURN(0); + } + /* Query hasn't started yet */ start_lineno= cur_file->lineno; DBUG_PRINT("info", ("Query hasn't started yet, start_lineno: %d", start_lineno)); } + + /* Skip all space at begining of line */ skip_char= 1; } else if (end_of_query(c)) @@ -5907,6 +6557,8 @@ int read_line(char *buf, int size) } + last_char= c; + if (!skip_char) { /* Could be a multibyte character */ @@ -5942,7 +6594,7 @@ int read_line(char *buf, int size) *p++= c; } } - die("The input buffer is too small for this query.x\n" \ + die("The input buffer is too small for this query.x\n" \ "check your query or increase MAX_QUERY and recompile"); DBUG_RETURN(0); } @@ -6116,9 +6768,10 @@ int read_command(struct st_command** command_ptr) DBUG_RETURN(1); } - convert_to_format_v1(read_command_buf); + if (opt_result_format_version == 1) + convert_to_format_v1(read_command_buf); - DBUG_PRINT("info", ("query: %s", read_command_buf)); + DBUG_PRINT("info", ("query: '%s'", read_command_buf)); if (*p == '#') { command->type= Q_COMMENT; @@ -6128,6 +6781,10 @@ int read_command(struct st_command** command_ptr) command->type= Q_COMMENT_WITH_COMMAND; p+= 2; /* Skip past -- */ } + else if (*p == '\n') + { + command->type= Q_EMPTY_LINE; + } /* Skip leading spaces */ while (*p && my_isspace(charset_info, *p)) @@ -6164,13 +6821,19 @@ static struct my_option my_long_options[] = 0, 0, 0, 0, 0, 0}, {"basedir", 'b', "Basedir for tests.", &opt_basedir, &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"character-sets-dir", OPT_CHARSETS_DIR, + {"character-sets-dir", 0, "Directory for character set files.", &opt_charsets_dir, &opt_charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"compress", 'C', "Use the compressed server/client protocol.", &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"cursor-protocol", OPT_CURSOR_PROTOCOL, "Use cursors for prepared statements.", + {"continue-on-error", 0, + "Continue test even if we got an error. " + "This is mostly useful when testing a storage engine to see what from a test file it can execute, " + "or to find all syntax errors in a newly created big test file", + &opt_continue_on_error, &opt_continue_on_error, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"cursor-protocol", 0, "Use cursors for prepared statements.", &cursor_protocol, &cursor_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"database", 'D', "Database to use.", &opt_db, &opt_db, 0, @@ -6182,32 +6845,27 @@ static struct my_option my_long_options[] = {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif - {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.", + {"debug-check", 0, "Check memory and open file usage at exit.", &debug_check_flag, &debug_check_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.", + {"debug-info", 0, "Print some debug info at exit.", &debug_info_flag, &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"global-subst", OPT_GLOBAL_SUBST, "argument should be 'X,Y' ;" - " substitute string X with another Y accross the whole test's current" - " result before comparing with expected result file", - &global_subst, &global_subst, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"host", 'h', "Connect to host.", &opt_host, &opt_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"include", 'i', "Include SQL before each test case.", &opt_include, - &opt_include, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"prologue", 0, "Include SQL before each test case.", &opt_prologue, + &opt_prologue, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"logdir", OPT_LOG_DIR, "Directory for log files", &opt_logdir, &opt_logdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"mark-progress", OPT_MARK_PROGRESS, + {"mark-progress", 0, "Write line number and elapsed time to <testname>.progress.", &opt_mark_progress, &opt_mark_progress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"max-connect-retries", OPT_MAX_CONNECT_RETRIES, + {"max-connect-retries", 0, "Maximum number of attempts to connect to server.", &opt_max_connect_retries, &opt_max_connect_retries, 0, GET_INT, REQUIRED_ARG, 500, 1, 10000, 0, 0, 0}, - {"max-connections", OPT_MAX_CONNECTIONS, + {"max-connections", 0, "Max number of open connections to server", &opt_max_connections, &opt_max_connections, 0, GET_INT, REQUIRED_ARG, DEFAULT_MAX_CONN, 8, 5120, 0, 0, 0}, @@ -6222,10 +6880,14 @@ static struct my_option my_long_options[] = #endif "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").", &opt_port, &opt_port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"ps-protocol", OPT_PS_PROTOCOL, + {"ps-protocol", 0, "Use prepared-statement protocol for communication.", &ps_protocol, &ps_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"non-blocking-api", 0, + "Use the non-blocking client API for communication.", + &non_blocking_api_enabled, &non_blocking_api_enabled, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"quiet", 's', "Suppress all normal output.", &silent, &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"record", 'r', "Record output of test_file into result file.", @@ -6233,40 +6895,37 @@ static struct my_option my_long_options[] = {"result-file", 'R', "Read/store result from/in this file.", &result_file_name, &result_file_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"result-format-version", OPT_RESULT_FORMAT_VERSION, + "Version of the result file format to use", + &opt_result_format_version, + &opt_result_format_version, 0, + GET_INT, REQUIRED_ARG, 1, 1, 2, 0, 0, 0}, {"server-arg", 'A', "Send option value to embedded server as a parameter.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"server-file", 'F', "Read embedded server arguments from file.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef HAVE_SMEM - {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME, + {"shared-memory-base-name", 0, "Base name of shared memory.", &shared_memory_base_name, &shared_memory_base_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, -#endif {"silent", 's', "Suppress all normal output. Synonym for --quiet.", &silent, &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-safemalloc", OPT_SKIP_SAFEMALLOC, - "Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG, - 0, 0, 0, 0, 0, 0}, {"sleep", 'T', "Always sleep this many seconds on sleep commands.", &opt_sleep, &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, -1, 0, 0, 0, 0}, {"socket", 'S', "The socket file to use for connection.", &unix_sock, &unix_sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"sp-protocol", OPT_SP_PROTOCOL, "Use stored procedures for select.", + {"sp-protocol", 0, "Use stored procedures for select.", &sp_protocol, &sp_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #include "sslopt-longopts.h" - {"tail-lines", OPT_TAIL_LINES, + {"tail-lines", 0, "Number of lines of the result to include in a failure report.", &opt_tail_lines, &opt_tail_lines, 0, GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0}, {"test-file", 'x', "Read test from/in this file (default stdin).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"connect-timeout", OPT_MY_CONNECT_TIMEOUT, "Client connection timeout", - (uchar**) &opt_connect_timeout, (uchar**) &opt_connect_timeout, 0, - GET_INT, REQUIRED_ARG, -1, -1, 0, 0, 0, 0}, {"timer-file", 'm', "File where the timing in microseconds is stored.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"tmpdir", 't', "Temporary directory where sockets are put.", @@ -6277,22 +6936,24 @@ static struct my_option my_long_options[] = GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"view-protocol", OPT_VIEW_PROTOCOL, "Use views for select.", + {"view-protocol", 0, "Use views for select.", &view_protocol, &view_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.", - (uchar**) &opt_plugin_dir, (uchar**) &opt_plugin_dir, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"default_auth", OPT_PLUGIN_DIR, - "Default authentication client-side plugin to use.", - (uchar**) &opt_default_auth, (uchar**) &opt_default_auth, 0, + {"connect_timeout", 0, + "Number of seconds before connection timeout.", + &opt_connect_timeout, &opt_connect_timeout, 0, GET_UINT, REQUIRED_ARG, + 120, 0, 3600 * 12, 0, 0, 0}, + {"plugin_dir", 0, "Directory for client-side plugins.", + &opt_plugin_dir, &opt_plugin_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"overlay-dir", 0, "Overlay directory.", &opt_overlay_dir, + &opt_overlay_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"suite-dir", 0, "Suite directory.", &opt_suite_dir, + &opt_suite_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; -#include <help_start.h> - void print_version(void) { printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,MTEST_VERSION, @@ -6310,8 +6971,6 @@ void usage() my_print_variables(my_long_options); } -#include <help_end.h> - /* Read arguments for embedded server and put them into @@ -6360,8 +7019,7 @@ void read_embedded_server_arguments(const char *name) static my_bool -get_one_option(int optid, const struct my_option *opt, - char *argument) +get_one_option(int optid, const struct my_option *opt, char *argument) { switch(optid) { case '#': @@ -6409,7 +7067,7 @@ get_one_option(int optid, const struct my_option *opt, argument= (char*) ""; // Don't require password if (argument) { - my_free(opt_pass, MYF(MY_ALLOW_ZERO_PTR)); + my_free(opt_pass); opt_pass= my_strdup(argument, MYF(MY_FAE)); while (*argument) *argument++= 'x'; /* Destroy argument */ tty_password= 0; @@ -6442,10 +7100,8 @@ get_one_option(int optid, const struct my_option *opt, case 'F': read_embedded_server_arguments(argument); break; - case OPT_SKIP_SAFEMALLOC: -#ifdef SAFEMALLOC - sf_malloc_quick=1; -#endif + case OPT_RESULT_FORMAT_VERSION: + set_result_format_version(opt_result_format_version); break; case 'V': print_version(); @@ -6466,7 +7122,9 @@ get_one_option(int optid, const struct my_option *opt, int parse_args(int argc, char **argv) { - load_defaults("my",load_default_groups,&argc,&argv); + if (load_defaults("my",load_default_groups,&argc,&argv)) + exit(1); + default_argv= argv; if ((handle_options(&argc, &argv, my_long_options, get_one_option))) @@ -6496,11 +7154,17 @@ int parse_args(int argc, char **argv) memcpy(global_subst_to, comma+1, strlen(comma)); } + if (!opt_suite_dir) + opt_suite_dir= "./"; + suite_dir_len= strlen(opt_suite_dir); + overlay_dir_len= opt_overlay_dir ? strlen(opt_overlay_dir) : 0; + if (!record) { /* Check that the result file exists */ if (result_file_name && access(result_file_name, F_OK) != 0) - die("The specified result file '%s' does not exist", result_file_name); + die("The specified result file '%s' does not exist", + result_file_name); } return 0; @@ -6589,6 +7253,8 @@ void init_win_path_patterns() "$MYSQL_TMP_DIR", "$MYSQLTEST_VARDIR", "$MASTER_MYSOCK", + "$MYSQL_SHAREDIR", + "$MYSQL_LIBDIR", "./test/" }; int num_paths= sizeof(paths)/sizeof(char*); int i; @@ -6613,7 +7279,7 @@ void init_win_path_patterns() /* Don't insert zero length strings in patterns array */ if (strlen(p) == 0) { - my_free(p, MYF(0)); + my_free(p); continue; } @@ -6637,7 +7303,7 @@ void free_win_path_patterns() for (i=0 ; i < patterns.elements ; i++) { const char** pattern= dynamic_element(&patterns, i, const char**); - my_free((char*) *pattern, MYF(0)); + my_free((void *) *pattern); } delete_dynamic(&patterns); } @@ -6825,8 +7491,8 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, } if (error != MYSQL_NO_DATA) - die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: error: %d", - error); + die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: " + "error: %d", error); if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: %d %s", mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); @@ -6834,12 +7500,12 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, for (i= 0; i < num_fields; i++) { /* Free data for output */ - my_free(my_bind[i].buffer, MYF(MY_WME | MY_FAE)); + my_free(my_bind[i].buffer); } /* Free array with bind structs, lengths and NULL flags */ - my_free(my_bind , MYF(MY_WME | MY_FAE)); - my_free(length , MYF(MY_WME | MY_FAE)); - my_free(is_null , MYF(MY_WME | MY_FAE)); + my_free(my_bind); + my_free(length); + my_free(is_null); } @@ -7024,21 +7690,13 @@ void run_query_normal(struct st_connection *cn, struct st_command *command, /* Send the query */ - if (do_send_query(cn, query, query_len, flags)) + if (do_send_query(cn, query, query_len)) { handle_error(command, mysql_errno(mysql), mysql_error(mysql), mysql_sqlstate(mysql), ds); goto end; } } -#ifdef EMBEDDED_LIBRARY - /* - Here we handle 'reap' command, so we need to check if the - query's thread was finished and probably wait - */ - else if (flags & QUERY_REAP_FLAG) - wait_query_thread_end(cn); -#endif /*EMBEDDED_LIBRARY*/ if (!(flags & QUERY_REAP_FLAG)) { cn->pending= TRUE; @@ -7051,7 +7709,7 @@ void run_query_normal(struct st_connection *cn, struct st_command *command, When on first result set, call mysql_read_query_result to retrieve answer to the query sent earlier */ - if ((counter==0) && mysql_read_query_result(mysql)) + if ((counter==0) && do_read_query_result(cn)) { /* we've failed to collect the result set */ cn->pending= TRUE; @@ -7073,8 +7731,6 @@ void run_query_normal(struct st_connection *cn, struct st_command *command, if (!disable_result_log) { - ulonglong UNINIT_VAR(affected_rows); /* Ok to be undef if 'disable_info' is set */ - if (res) { MYSQL_FIELD *fields= mysql_fetch_fields(res); @@ -7091,10 +7747,10 @@ void run_query_normal(struct st_connection *cn, struct st_command *command, /* Need to call mysql_affected_rows() before the "new" - query to find the warnings + query to find the warnings. */ if (!disable_info) - affected_rows= mysql_affected_rows(mysql); + append_info(ds, mysql_affected_rows(mysql), mysql_info(mysql)); /* Add all warnings to the result. We can't do this if we are in @@ -7109,9 +7765,6 @@ void run_query_normal(struct st_connection *cn, struct st_command *command, dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length); } } - - if (!disable_info) - append_info(ds, affected_rows, mysql_info(mysql)); } if (res) @@ -7132,6 +7785,7 @@ void run_query_normal(struct st_connection *cn, struct st_command *command, /* If we come here the query is both executed and read successfully */ handle_no_error(command); + revert_properties(); end: @@ -7184,7 +7838,8 @@ static int match_expected_error(struct st_command *command, NULL is quite likely, but not in conjunction with a SQL-state expect! */ if (unlikely(err_sqlstate == NULL)) - die("expecting a SQL-state (%s) from query '%s' which cannot produce one...", + die("expecting a SQL-state (%s) from query '%s' which cannot " + "produce one...", command->expected_errors.err[i].code.sqlstate, command->query); if (strncmp(command->expected_errors.err[i].code.sqlstate, @@ -7238,7 +7893,11 @@ void handle_error(struct st_command *command, } if (command->abort_on_error) - die("query '%s' failed: %d: %s", command->query, err_errno, err_error); + { + report_or_die("query '%s' failed: %d: %s", command->query, err_errno, + err_error); + DBUG_VOID_RETURN; + } DBUG_PRINT("info", ("expected_errors.count: %d", command->expected_errors.count)); @@ -7265,6 +7924,7 @@ void handle_error(struct st_command *command, dynstr_append(ds,"Got one of the listed errors\n"); } /* OK */ + revert_properties(); DBUG_VOID_RETURN; } @@ -7283,15 +7943,18 @@ void handle_error(struct st_command *command, if (command->expected_errors.count > 0) { if (command->expected_errors.err[0].type == ERR_ERRNO) - die("query '%s' failed with wrong errno %d: '%s', instead of %d...", - command->query, err_errno, err_error, - command->expected_errors.err[0].code.errnum); + report_or_die("query '%s' failed with wrong errno %d: '%s', instead of " + "%d...", + command->query, err_errno, err_error, + command->expected_errors.err[0].code.errnum); else - die("query '%s' failed with wrong sqlstate %s: '%s', instead of %s...", - command->query, err_sqlstate, err_error, - command->expected_errors.err[0].code.sqlstate); + report_or_die("query '%s' failed with wrong sqlstate %s: '%s', " + "instead of %s...", + command->query, err_sqlstate, err_error, + command->expected_errors.err[0].code.sqlstate); } + revert_properties(); DBUG_VOID_RETURN; } @@ -7315,17 +7978,18 @@ void handle_no_error(struct st_command *command) command->expected_errors.err[0].code.errnum != 0) { /* Error code we wanted was != 0, i.e. not an expected success */ - die("query '%s' succeeded - should have failed with errno %d...", - command->query, command->expected_errors.err[0].code.errnum); + report_or_die("query '%s' succeeded - should have failed with errno %d...", + command->query, command->expected_errors.err[0].code.errnum); } else if (command->expected_errors.err[0].type == ERR_SQLSTATE && strcmp(command->expected_errors.err[0].code.sqlstate,"00000") != 0) { /* SQLSTATE we wanted was != "00000", i.e. not an expected success */ - die("query '%s' succeeded - should have failed with sqlstate %s...", - command->query, command->expected_errors.err[0].code.sqlstate); + report_or_die("query '%s' succeeded - should have failed with " + "sqlstate %s...", + command->query, + command->expected_errors.err[0].code.sqlstate); } - DBUG_VOID_RETURN; } @@ -7453,9 +8117,6 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, handle_no_error(command); if (!disable_result_log) { - ulonglong affected_rows; - LINT_INIT(affected_rows); - /* Not all statements creates a result set. If there is one we can now create another normal result set that contains the meta @@ -7498,11 +8159,11 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, } /* - Need to grab affected rows information before getting - warnings here + Fetch info before fetching warnings, since it will be reset + otherwise. */ if (!disable_info) - affected_rows= mysql_affected_rows(mysql); + append_info(ds, mysql_stmt_affected_rows(stmt), mysql_info(mysql)); if (!disable_warnings) { @@ -7526,8 +8187,6 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, ds_execute_warnings.length); } } - if (!disable_info) - append_info(ds, affected_rows, mysql_info(mysql)); } end: @@ -7545,6 +8204,8 @@ end: var_set_errno(mysql_stmt_errno(stmt)); + revert_properties(); + /* Close the statement if reconnect, need new prepare */ if (mysql->reconnect) { @@ -7575,8 +8236,13 @@ int util_query(MYSQL* org_mysql, const char* query){ if (!(mysql= mysql_init(mysql))) die("Failed in mysql_init()"); + if (opt_connect_timeout) + mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, + (void *) &opt_connect_timeout); + /* enable local infile, in non-binary builds often disabled by default */ mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, 0); + mysql_options(mysql, MYSQL_OPT_NONBLOCK, 0); safe_connect(mysql, "util", org_mysql->host, org_mysql->user, org_mysql->passwd, org_mysql->db, org_mysql->port, org_mysql->unix_socket); @@ -7620,12 +8286,14 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) DBUG_ENTER("run_query"); if (cn->pending && (flags & QUERY_SEND_FLAG)) - die ("Cannot run query on connection between send and reap"); + die("Cannot run query on connection between send and reap"); if (!(flags & QUERY_SEND_FLAG) && !cn->pending) - die ("Cannot reap on a connection without pending send"); + die("Cannot reap on a connection without pending send"); init_dynamic_string(&ds_warnings, NULL, 0, 256); + ds_warn= &ds_warnings; + /* Evaluate query if this is an eval command */ @@ -7791,7 +8459,8 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) ds, &ds_warnings); dynstr_free(&ds_warnings); - if (command->type == Q_EVAL) + ds_warn= 0; + if (command->type == Q_EVAL || command->type == Q_SEND_EVAL) dynstr_free(&eval_query); if (display_result_sorted) @@ -7805,13 +8474,14 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) if (sp_created) { if (util_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp ")) - die("Failed to drop sp: %d: %s", mysql_errno(mysql), mysql_error(mysql)); + report_or_die("Failed to drop sp: %d: %s", mysql_errno(mysql), + mysql_error(mysql)); } if (view_created) { if (util_query(mysql, "DROP VIEW mysqltest_tmp_v ")) - die("Failed to drop view: %d: %s", + report_or_die("Failed to drop view: %d: %s", mysql_errno(mysql), mysql_error(mysql)); } @@ -7837,8 +8507,8 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) char *re_eprint(int err) { static char epbuf[100]; - size_t len= my_regerror(REG_ITOA|err, (my_regex_t *)NULL, - epbuf, sizeof(epbuf)); + size_t len __attribute__((unused))= + my_regerror(REG_ITOA|err, (my_regex_t *)NULL, epbuf, sizeof(epbuf)); assert(len <= sizeof(epbuf)); return(epbuf); } @@ -7947,7 +8617,7 @@ void get_command_type(struct st_command* command) save= command->query[command->first_word_len]; command->query[command->first_word_len]= 0; - type= find_type(command->query, &command_typelib, 1+2); + type= find_type(command->query, &command_typelib, FIND_TYPE_NO_PREFIX); command->query[command->first_word_len]= save; if (type > 0) { @@ -7975,9 +8645,10 @@ void get_command_type(struct st_command* command) else { /* -- "comment" that didn't contain a mysqltest command */ - die("Found line beginning with -- that didn't contain "\ - "a valid mysqltest command, check your syntax or "\ + report_or_die("Found line beginning with -- that didn't contain " \ + "a valid mysqltest command, check your syntax or " \ "use # if you intended to write a comment"); + command->type= Q_COMMENT; } } @@ -8047,14 +8718,17 @@ static void dump_backtrace(void) fprintf(stderr, "read_command_buf (%p): ", read_command_buf); my_safe_print_str(read_command_buf, sizeof(read_command_buf)); + fputc('\n', stderr); if (conn) { fprintf(stderr, "conn->name (%p): ", conn->name); my_safe_print_str(conn->name, conn->name_len); + fputc('\n', stderr); #ifdef EMBEDDED_LIBRARY fprintf(stderr, "conn->cur_query (%p): ", conn->cur_query); my_safe_print_str(conn->cur_query, conn->cur_query_len); + fputc('\n', stderr); #endif } fputs("Attempting backtrace...\n", stderr); @@ -8159,6 +8833,9 @@ int main(int argc, char **argv) MY_INIT(argv[0]); DBUG_ENTER("main"); + /* mysqltest has no way to free all its memory correctly */ + sf_leaking_memory= 1; + save_file[0]= 0; TMPDIR[0]= 0; @@ -8189,7 +8866,7 @@ int main(int argc, char **argv) my_init_dynamic_array(&q_lines, sizeof(struct st_command*), 1024, 1024); - if (hash_init2(&var_hash, 64, charset_info, + if (my_hash_init2(&var_hash, 64, charset_info, 128, 0, 0, get_var_key, var_free, MYF(0))) die("Variable hash initialization failed"); @@ -8237,6 +8914,7 @@ int main(int argc, char **argv) next_con= connections + 1; var_set_int("$PS_PROTOCOL", ps_protocol); + var_set_int("$NON_BLOCKING_API", non_blocking_api_enabled); var_set_int("$SP_PROTOCOL", sp_protocol); var_set_int("$VIEW_PROTOCOL", view_protocol); var_set_int("$CURSOR_PROTOCOL", cursor_protocol); @@ -8264,6 +8942,7 @@ int main(int argc, char **argv) cur_file->file_name= my_strdup("<stdin>", MYF(MY_WME)); cur_file->lineno= 1; } + var_set_string("MYSQLTEST_FILE", cur_file->file_name); init_re(); /* Cursor protcol implies ps protocol */ @@ -8276,8 +8955,12 @@ int main(int argc, char **argv) cursor_protocol_enabled= cursor_protocol; st_connection *con= connections; + init_connection_thd(con); if (! (con->mysql= mysql_init(0))) die("Failed in mysql_init()"); + if (opt_connect_timeout) + mysql_options(con->mysql, MYSQL_OPT_CONNECT_TIMEOUT, + (void *) &opt_connect_timeout); if (opt_compress) mysql_options(con->mysql,MYSQL_OPT_COMPRESS,NullS); mysql_options(con->mysql, MYSQL_OPT_LOCAL_INFILE, 0); @@ -8293,10 +8976,7 @@ int main(int argc, char **argv) if (opt_plugin_dir && *opt_plugin_dir) mysql_options(con->mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir); - if (opt_default_auth && *opt_default_auth) - mysql_options(con->mysql, MYSQL_DEFAULT_AUTH, opt_default_auth); - -#ifdef HAVE_OPENSSL +#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) if (opt_use_ssl) { @@ -8318,6 +8998,7 @@ int main(int argc, char **argv) if (!(con->name = my_strdup("default", MYF(MY_WME)))) die("Out of memory"); + mysql_options(con->mysql, MYSQL_OPT_NONBLOCK, 0); safe_connect(con->mysql, con->name, opt_host, opt_user, opt_pass, opt_db, opt_port, unix_sock); @@ -8334,9 +9015,9 @@ int main(int argc, char **argv) set_current_connection(con); - if (opt_include) + if (opt_prologue) { - open_file(opt_include); + open_file(opt_prologue); } verbose_msg("Start processing test commands from '%s' ...", cur_file->file_name); @@ -8402,66 +9083,49 @@ int main(int argc, char **argv) case Q_DISCONNECT: case Q_DIRTY_CLOSE: do_close_connection(command); break; - case Q_RPL_PROBE: do_rpl_probe(command); break; - case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(command); break; - case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(command); break; case Q_ENABLE_PREPARE_WARNINGS: prepare_warnings_enabled=1; break; case Q_DISABLE_PREPARE_WARNINGS: prepare_warnings_enabled=0; break; case Q_ENABLE_QUERY_LOG: - disable_query_log= 0; - var_set_int("$ENABLED_QUERY_LOG", 1); + set_property(command, P_QUERY, 0); break; case Q_DISABLE_QUERY_LOG: - disable_query_log= 1; - var_set_int("$ENABLED_QUERY_LOG", 0); + set_property(command, P_QUERY, 1); break; case Q_ENABLE_ABORT_ON_ERROR: - abort_on_error= 1; - var_set_int("$ENABLED_ABORT_ON_ERROR", 1); + set_property(command, P_ABORT, 1); break; case Q_DISABLE_ABORT_ON_ERROR: - abort_on_error= 0; - var_set_int("$ENABLED_ABORT_ON_ERROR", 0); + set_property(command, P_ABORT, 0); break; case Q_ENABLE_RESULT_LOG: - disable_result_log= 0; - var_set_int("$ENABLED_RESULT_LOG", 1); + set_property(command, P_RESULT, 0); break; case Q_DISABLE_RESULT_LOG: - disable_result_log=1; - var_set_int("$ENABLED_RESULT_LOG", 0); + set_property(command, P_RESULT, 1); break; case Q_ENABLE_CONNECT_LOG: - disable_connect_log=0; - var_set_int("$ENABLED_CONNECT_LOG", 1); + set_property(command, P_CONNECT, 0); break; case Q_DISABLE_CONNECT_LOG: - disable_connect_log=1; - var_set_int("$ENABLED_CONNECT_LOG", 0); + set_property(command, P_CONNECT, 1); break; case Q_ENABLE_WARNINGS: - disable_warnings= 0; - var_set_int("$ENABLED_WARNINGS", 1); + set_property(command, P_WARN, 0); break; case Q_DISABLE_WARNINGS: - disable_warnings= 1; - var_set_int("$ENABLED_WARNINGS", 0); + set_property(command, P_WARN, 1); break; case Q_ENABLE_INFO: - disable_info= 0; - var_set_int("$ENABLED_INFO", 1); + set_property(command, P_INFO, 0); break; case Q_DISABLE_INFO: - disable_info= 1; - var_set_int("$ENABLED_INFO", 0); + set_property(command, P_INFO, 1); break; case Q_ENABLE_METADATA: - display_metadata= 1; - var_set_int("$ENABLED_METADATA", 1); + set_property(command, P_META, 1); break; case Q_DISABLE_METADATA: - display_metadata= 0; - var_set_int("$ENABLED_METADATA", 0); + set_property(command, P_META, 0); break; case Q_ENABLE_COLUMN_NAMES: disable_column_names= 0; @@ -8501,6 +9165,7 @@ int main(int argc, char **argv) case Q_MOVE_FILE: do_move_file(command); break; case Q_CHMOD_FILE: do_chmod_file(command); break; case Q_PERL: do_perl(command); break; + case Q_RESULT_FORMAT_VERSION: do_result_format_version(command); break; case Q_DELIMITER: do_delimiter(command); break; @@ -8627,9 +9292,38 @@ int main(int argc, char **argv) do_sync_with_master2(command, 0); break; } - case Q_COMMENT: /* Ignore row */ + case Q_COMMENT: + { command->last_argument= command->end; + + /* Don't output comments in v1 */ + if (opt_result_format_version == 1) + break; + + /* Don't output comments if query logging is off */ + if (disable_query_log) + break; + + /* Write comment's with two starting #'s to result file */ + const char* p= command->query; + if (p && *p == '#' && *(p+1) == '#') + { + dynstr_append_mem(&ds_res, command->query, command->query_len); + dynstr_append(&ds_res, "\n"); + } break; + } + case Q_EMPTY_LINE: + /* Don't output newline in v1 */ + if (opt_result_format_version == 1) + break; + + /* Don't output newline if query logging is off */ + if (disable_query_log) + break; + + dynstr_append(&ds_res, "\n"); + break; case Q_PING: handle_command_error(command, mysql_ping(cur_con->mysql), -1); break; @@ -8657,12 +9351,18 @@ int main(int argc, char **argv) do_set_charset(command); break; case Q_DISABLE_PS_PROTOCOL: - ps_protocol_enabled= 0; + set_property(command, P_PS, 0); /* Close any open statements */ close_statements(); break; case Q_ENABLE_PS_PROTOCOL: - ps_protocol_enabled= ps_protocol; + set_property(command, P_PS, ps_protocol); + break; + case Q_DISABLE_NON_BLOCKING_API: + non_blocking_api_enabled= 0; + break; + case Q_ENABLE_NON_BLOCKING_API: + non_blocking_api_enabled= 1; break; case Q_DISABLE_RECONNECT: set_reconnect(cur_con->mysql, 0); @@ -8676,7 +9376,7 @@ int main(int argc, char **argv) if (parsing_disabled == 0) parsing_disabled= 1; else - die("Parsing is already disabled"); + report_or_die("Parsing is already disabled"); break; case Q_ENABLE_PARSING: /* @@ -8686,7 +9386,7 @@ int main(int argc, char **argv) if (parsing_disabled == 1) parsing_disabled= 0; else - die("Parsing is already enabled"); + report_or_die("Parsing is already enabled"); break; case Q_DIE: /* Abort test with error code and error message */ @@ -8890,13 +9590,14 @@ void do_get_replace_column(struct st_command *command) if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS) die("Wrong column number to replace_column in '%s'", command->query); if (!*from) - die("Wrong number of arguments to replace_column in '%s'", command->query); + die("Wrong number of arguments to replace_column in '%s'", + command->query); to= get_string(&buff, &from, command); - my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR); + my_free(replace_column[column_number-1]); replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE)); set_if_bigger(max_replace_column, column_number); } - my_free(start, MYF(0)); + my_free(start); command->last_argument= command->end; DBUG_VOID_RETURN; @@ -8910,7 +9611,7 @@ void free_replace_column() { if (replace_column[i]) { - my_free(replace_column[i], 0); + my_free(replace_column[i]); replace_column[i]= 0; } } @@ -8928,20 +9629,15 @@ void free_replace_column() typedef struct st_pointer_array { /* when using array-strings */ TYPELIB typelib; /* Pointer to strings */ uchar *str; /* Strings is here */ - int7 *flag; /* Flag about each var. */ + uint8 *flag; /* Flag about each var. */ uint array_allocs,max_count,length,max_length; } POINTER_ARRAY; -struct st_replace; struct st_replace *init_replace(char * *from, char * *to, uint count, char * word_end_chars); int insert_pointer_name(reg1 POINTER_ARRAY *pa,char * name); -void replace_strings_append(struct st_replace *rep, DYNAMIC_STRING* ds, - const char *from, int len); void free_pointer_array(POINTER_ARRAY *pa); -struct st_replace *glob_replace; - /* Get arguments for replace. The syntax is: replace from to [from to ...] @@ -8991,7 +9687,7 @@ void do_get_replace(struct st_command *command) die("Can't initialize replace from '%s'", command->query); free_pointer_array(&from_array); free_pointer_array(&to_array); - my_free(start, MYF(0)); + my_free(start); command->last_argument= command->end; DBUG_VOID_RETURN; } @@ -9000,11 +9696,8 @@ void do_get_replace(struct st_command *command) void free_replace() { DBUG_ENTER("free_replace"); - if (glob_replace) - { - my_free(glob_replace,MYF(0)); - glob_replace=0; - } + my_free(glob_replace); + glob_replace= NULL; DBUG_VOID_RETURN; } @@ -9088,26 +9781,6 @@ struct st_regex int icase; /* true if the match is case insensitive */ }; -struct st_replace_regex -{ - DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */ - - /* - Temporary storage areas for substitutions. To reduce unnessary copying - and memory freeing/allocation, we pre-allocate two buffers, and alternate - their use, one for input/one for output, the roles changing on the next - st_regex substition. At the end of substitutions buf points to the - one containing the final result. - */ - char* buf; - char* even_buf; - char* odd_buf; - int even_buf_len; - int odd_buf_len; -}; - -struct st_replace_regex *glob_replace_regex= 0; - int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace, char *string, int icase); @@ -9224,7 +9897,7 @@ struct st_replace_regex* init_replace_regex(char* expr) return res; err: - my_free(res,0); + my_free(res); die("Error parsing replace_regex \"%s\"", expr); return 0; } @@ -9306,7 +9979,13 @@ void do_get_replace_regex(struct st_command *command) { char *expr= command->first_argument; free_replace_regex(); - if (!(glob_replace_regex=init_replace_regex(expr))) + /* Allow variable for the *entire* list of replacements */ + if (*expr == '$') + { + VAR *val= var_get(expr, NULL, 0, 1); + expr= val ? val->str_val : NULL; + } + if (expr && *expr && !(glob_replace_regex=init_replace_regex(expr))) die("Could not init replace_regex"); command->last_argument= command->end; } @@ -9316,9 +9995,9 @@ void free_replace_regex() if (glob_replace_regex) { delete_dynamic(&glob_replace_regex->regex_arr); - my_free(glob_replace_regex->even_buf,MYF(MY_ALLOW_ZERO_PTR)); - my_free(glob_replace_regex->odd_buf,MYF(MY_ALLOW_ZERO_PTR)); - my_free(glob_replace_regex,MYF(0)); + my_free(glob_replace_regex->even_buf); + my_free(glob_replace_regex->odd_buf); + my_free(glob_replace_regex); glob_replace_regex=0; } } @@ -9513,7 +10192,7 @@ int reg_replace(char** buf_p, int* buf_len_p, char *pattern, str_p= str_end; } } - my_free(subs, MYF(0)); + my_free(subs); my_regfree(&r); *res_p= 0; *buf_p= buf; @@ -9637,7 +10316,7 @@ REPLACE *init_replace(char * *from, char * *to,uint count, free_sets(&sets); DBUG_RETURN(0); } - VOID(make_new_set(&sets)); /* Set starting set */ + (void) make_new_set(&sets); /* Set starting set */ make_sets_invisible(&sets); /* Hide previus sets */ used_sets=-1; word_states=make_new_set(&sets); /* Start of new word */ @@ -9645,7 +10324,7 @@ REPLACE *init_replace(char * *from, char * *to,uint count, if (!(follow=(FOLLOWS*) my_malloc((states+2)*sizeof(FOLLOWS),MYF(MY_WME)))) { free_sets(&sets); - my_free(found_set,MYF(0)); + my_free(found_set); DBUG_RETURN(0); } @@ -9839,9 +10518,9 @@ REPLACE *init_replace(char * *from, char * *to,uint count, replace[i].next[j]=(REPLACE*) (rep_str+(-sets.set[i].next[j]-1)); } } - my_free(follow,MYF(0)); + my_free(follow); free_sets(&sets); - my_free(found_set,MYF(0)); + my_free(found_set); DBUG_PRINT("exit",("Replace table has %d states",sets.count)); DBUG_RETURN(replace); } @@ -9857,7 +10536,7 @@ int init_sets(REP_SETS *sets,uint states) if (!(sets->bit_buffer=(uint*) my_malloc(sizeof(uint)*sets->size_of_bits* SET_MALLOC_HUNC,MYF(MY_WME)))) { - my_free(sets->set,MYF(0)); + my_free(sets->set); return 1; } return 0; @@ -9918,8 +10597,8 @@ void free_last_set(REP_SETS *sets) void free_sets(REP_SETS *sets) { - my_free(sets->set_buffer,MYF(0)); - my_free(sets->bit_buffer,MYF(0)); + my_free(sets->set_buffer); + my_free(sets->bit_buffer); return; } @@ -10057,12 +10736,12 @@ int insert_pointer_name(reg1 POINTER_ARRAY *pa,char * name) if (!(pa->str= (uchar*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD), MYF(MY_WME)))) { - my_free((char*) pa->typelib.type_names,MYF(0)); + my_free(pa->typelib.type_names); DBUG_RETURN (-1); } pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(uchar*)+ sizeof(*pa->flag)); - pa->flag= (int7*) (pa->typelib.type_names+pa->max_count); + pa->flag= (uint8*) (pa->typelib.type_names+pa->max_count); pa->length=0; pa->max_length=PS_MALLOC-MALLOC_OVERHEAD; pa->array_allocs=1; @@ -10098,14 +10777,14 @@ int insert_pointer_name(reg1 POINTER_ARRAY *pa,char * name) pa->typelib.type_names=new_array; old_count=pa->max_count; pa->max_count=len/(sizeof(uchar*) + sizeof(*pa->flag)); - pa->flag= (int7*) (pa->typelib.type_names+pa->max_count); + pa->flag= (uint8*) (pa->typelib.type_names+pa->max_count); memcpy((uchar*) pa->flag,(char *) (pa->typelib.type_names+old_count), old_count*sizeof(*pa->flag)); } pa->flag[pa->typelib.count]=0; /* Reset flag */ pa->typelib.type_names[pa->typelib.count++]= (char*) pa->str+pa->length; pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */ - VOID(strmov((char*) pa->str+pa->length,name)); + (void) strmov((char*) pa->str+pa->length,name); pa->length+=length; DBUG_RETURN(0); } /* insert_pointer_name */ @@ -10118,9 +10797,9 @@ void free_pointer_array(POINTER_ARRAY *pa) if (pa->typelib.count) { pa->typelib.count=0; - my_free((char*) pa->typelib.type_names,MYF(0)); + my_free(pa->typelib.type_names); pa->typelib.type_names=0; - my_free(pa->str,MYF(0)); + my_free(pa->str); } } /* free_pointer_array */ diff --git a/client/readline.cc b/client/readline.cc index b44862062e1..791a044e0e1 100644 --- a/client/readline.cc +++ b/client/readline.cc @@ -47,7 +47,7 @@ LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file) return 0; if (init_line_buffer(line_buff,my_fileno(file),IO_SIZE,max_size)) { - my_free(line_buff,MYF(0)); + my_free(line_buff); return 0; } return line_buff; @@ -75,8 +75,8 @@ void batch_readline_end(LINE_BUFFER *line_buff) { if (line_buff) { - my_free(line_buff->buffer,MYF(MY_ALLOW_ZERO_PTR)); - my_free(line_buff,MYF(0)); + my_free(line_buff->buffer); + my_free(line_buff); } } @@ -89,7 +89,7 @@ LINE_BUFFER *batch_readline_command(LINE_BUFFER *line_buff, char * str) return 0; if (init_line_buffer_from_string(line_buff,str)) { - my_free(line_buff,MYF(0)); + my_free(line_buff); return 0; } return line_buff; diff --git a/client/sql_string.cc b/client/sql_string.cc.dontuse index 57518423f4b..64219886dd0 100644 --- a/client/sql_string.cc +++ b/client/sql_string.cc.dontuse @@ -25,18 +25,20 @@ #include <my_sys.h> #include <m_string.h> #include <m_ctype.h> -#ifdef HAVE_FCONVERT -#include <floatingpoint.h> -#endif +#include <mysql_com.h> + #include "sql_string.h" /***************************************************************************** ** String functions *****************************************************************************/ -bool String::real_alloc(uint32 arg_length) +bool String::real_alloc(uint32 length) { - arg_length=ALIGN_SIZE(arg_length+1); + uint32 arg_length= ALIGN_SIZE(length + 1); + DBUG_ASSERT(arg_length > length); + if (arg_length <= length) + return TRUE; /* Overflow */ str_length=0; if (Alloced_length < arg_length) { @@ -59,6 +61,9 @@ bool String::real_alloc(uint32 arg_length) bool String::realloc(uint32 alloc_length) { uint32 len=ALIGN_SIZE(alloc_length+1); + DBUG_ASSERT(len > alloc_length); + if (len <= alloc_length) + return TRUE; /* Overflow */ if (Alloced_length < len) { char *new_ptr; @@ -111,83 +116,17 @@ bool String::set(double num,uint decimals, CHARSET_INFO *cs) { char buff[FLOATING_POINT_BUFFER]; uint dummy_errors; + size_t len; str_charset=cs; if (decimals >= NOT_FIXED_DEC) { - uint32 len= my_sprintf(buff,(buff, "%.15g",num));// Enough for a DATETIME + len= my_gcvt(num, MY_GCVT_ARG_DOUBLE, sizeof(buff) - 1, buff, NULL); return copy(buff, len, &my_charset_latin1, cs, &dummy_errors); } -#ifdef HAVE_FCONVERT - int decpt,sign; - char *pos,*to; - - VOID(fconvert(num,(int) decimals,&decpt,&sign,buff+1)); - if (!my_isdigit(&my_charset_latin1, buff[1])) - { // Nan or Inf - pos=buff+1; - if (sign) - { - buff[0]='-'; - pos=buff; - } - uint dummy_errors; - return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs, &dummy_errors); - } - if (alloc((uint32) ((uint32) decpt+3+decimals))) - return TRUE; - to=Ptr; - if (sign) - *to++='-'; - - pos=buff+1; - if (decpt < 0) - { /* value is < 0 */ - *to++='0'; - if (!decimals) - goto end; - *to++='.'; - if ((uint32) -decpt > decimals) - decpt= - (int) decimals; - decimals=(uint32) ((int) decimals+decpt); - while (decpt++ < 0) - *to++='0'; - } - else if (decpt == 0) - { - *to++= '0'; - if (!decimals) - goto end; - *to++='.'; - } - else - { - while (decpt-- > 0) - *to++= *pos++; - if (!decimals) - goto end; - *to++='.'; - } - while (decimals--) - *to++= *pos++; - -end: - *to=0; - str_length=(uint32) (to-Ptr); - return FALSE; -#else -#ifdef HAVE_SNPRINTF - buff[sizeof(buff)-1]=0; // Safety - IF_DBUG(int num_chars= ) - snprintf(buff, sizeof(buff)-1, "%.*f",(int) decimals, num); - DBUG_ASSERT(num_chars > 0); - DBUG_ASSERT(num_chars < (int) sizeof(buff)); -#else - sprintf(buff,"%.*f",(int) decimals,num); -#endif - return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs, + len= my_fcvt(num, decimals, buff, NULL); + return copy(buff, (uint32) len, &my_charset_latin1, cs, &dummy_errors); -#endif } @@ -670,7 +609,8 @@ void String::qs_append(const char *str, uint32 len) void String::qs_append(double d) { char *buff = Ptr + str_length; - str_length+= my_sprintf(buff, (buff, "%.15g", d)); + str_length+= my_gcvt(d, MY_GCVT_ARG_DOUBLE, FLOATING_POINT_BUFFER - 1, buff, + NULL); } void String::qs_append(double *d) diff --git a/client/sql_string.h b/client/sql_string.h.dontuse index 6adf8f91fd0..67155ebcee7 100644 --- a/client/sql_string.h +++ b/client/sql_string.h.dontuse @@ -1,5 +1,7 @@ -/* - Copyright (c) 2000, 2012, Oracle and/or its affiliates. +#ifndef SQL_STRING_INCLUDED +#define SQL_STRING_INCLUDED + +/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,22 +14,14 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* This file is originally from the mysql distribution. Coded by monty */ -#ifndef CLIENT_SQL_STRING_H -#define CLIENT_SQL_STRING_H - #ifdef USE_PRAGMA_INTERFACE #pragma interface /* gcc class implementation */ #endif -#ifndef NOT_FIXED_DEC -#define NOT_FIXED_DEC 31 -#endif - 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); @@ -38,13 +32,13 @@ uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, class String { char *Ptr; - uint32 str_length,Alloced_length; + uint32 str_length,Alloced_length, extra_alloc; bool alloced; CHARSET_INFO *str_charset; public: String() { - Ptr=0; str_length=Alloced_length=0; alloced=0; + Ptr=0; str_length=Alloced_length=extra_alloc=0; alloced=0; str_charset= &my_charset_bin; } String(uint32 length_arg) @@ -54,23 +48,24 @@ public: } String(const char *str, CHARSET_INFO *cs) { - Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0; + Ptr=(char*) str; str_length= (uint32) strlen(str); + Alloced_length= extra_alloc= 0; alloced=0; str_charset=cs; } String(const char *str,uint32 len, CHARSET_INFO *cs) { - Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0; + Ptr=(char*) str; str_length=len; Alloced_length= extra_alloc=0; alloced=0; str_charset=cs; } String(char *str,uint32 len, CHARSET_INFO *cs) { - Ptr=(char*) str; Alloced_length=str_length=len; alloced=0; + Ptr=(char*) str; Alloced_length=str_length=len; extra_alloc= 0; alloced=0; str_charset=cs; } String(const String &str) { Ptr=str.Ptr ; str_length=str.str_length ; - Alloced_length=str.Alloced_length; alloced=0; + Alloced_length=str.Alloced_length; extra_alloc= 0; alloced=0; str_charset=str.str_charset; } static void *operator new(size_t size, MEM_ROOT *mem_root) @@ -185,7 +180,7 @@ public: { alloced=0; Alloced_length=0; - my_free(Ptr,MYF(0)); + my_free(Ptr); Ptr=0; str_length=0; /* Safety */ } @@ -367,4 +362,4 @@ public: } }; -#endif +#endif /* SQL_STRING_INCLUDED */ |