diff options
549 files changed, 20492 insertions, 5340 deletions
diff --git a/.bzrignore b/.bzrignore index d2a1ce94f70..a7a7e395347 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1922,3 +1922,4 @@ libmysqld/examples/mysqltest.cc extra/libevent/event-config.h libmysqld/opt_table_elimination.cc libmysqld/ha_federatedx.cc +libmysqld/debug_sync.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index cccd42205b1..0d7380c8f75 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,12 @@ IF(EXTRA_DEBUG) ADD_DEFINITIONS(-D EXTRA_DEBUG) ENDIF(EXTRA_DEBUG) +IF(ENABLED_DEBUG_SYNC) + ADD_DEFINITIONS(-D ENABLED_DEBUG_SYNC) +ENDIF(ENABLED_DEBUG_SYNC) +SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DENABLED_DEBUG_SYNC") +SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DENABLED_DEBUG_SYNC") + # in some places we use DBUG_OFF SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DDBUG_OFF") SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DDBUG_OFF") @@ -211,12 +217,16 @@ ENDIF(WITHOUT_DYNAMIC_PLUGINS) FILE(GLOB STORAGE_SUBDIRS storage/*) FOREACH(SUBDIR ${STORAGE_SUBDIRS}) FILE(RELATIVE_PATH DIRNAME ${PROJECT_SOURCE_DIR}/storage ${SUBDIR}) - STRING(TOUPPER ${DIRNAME} ENGINE) - STRING(TOLOWER ${DIRNAME} ENGINE_LOWER) IF (EXISTS ${SUBDIR}/CMakeLists.txt) # Check MYSQL_STORAGE_ENGINE macro is present FILE(STRINGS ${SUBDIR}/CMakeLists.txt HAVE_STORAGE_ENGINE REGEX MYSQL_STORAGE_ENGINE) IF(HAVE_STORAGE_ENGINE) + # Extract name of engine from HAVE_STORAGE_ENGINE + STRING(REGEX REPLACE ".*MYSQL_STORAGE_ENGINE\\((.*\)\\).*" + "\\1" ENGINE_NAME ${HAVE_STORAGE_ENGINE}) + STRING(TOUPPER ${ENGINE_NAME} ENGINE) + STRING(TOLOWER ${ENGINE_NAME} ENGINE_LOWER) + SET(ENGINE_BUILD_TYPE "DYNAMIC") # Read plug.in to find out if a plugin is mandatory and whether it supports # build as shared library (dynamic). @@ -254,6 +264,7 @@ FOREACH(SUBDIR ${STORAGE_SUBDIRS}) SET (MYSQLD_STATIC_ENGINE_LIBS ${MYSQLD_STATIC_ENGINE_LIBS} ${PLUGIN_NAME}) SET (STORAGE_ENGINE_DEFS "${STORAGE_ENGINE_DEFS} -DWITH_${ENGINE}_STORAGE_ENGINE") SET (WITH_${ENGINE}_STORAGE_ENGINE TRUE) + SET (${ENGINE}_DIR ${DIRNAME}) ENDIF (ENGINE_BUILD_TYPE STREQUAL "STATIC") ENDIF(EXISTS ${SUBDIR}/plug.in) diff --git a/Makefile.am b/Makefile.am index 5d076adcda0..d282bd64716 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -# Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +# Copyright 2000-2008 MySQL AB, 2009 Sun Microsystems, Inc. # # 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 @@ -26,7 +26,7 @@ EXTRA_DIST = INSTALL-SOURCE INSTALL-WIN-SOURCE \ SUBDIRS = . include @docs_dirs@ @zlib_dir@ \ @readline_topdir@ sql-common scripts \ @pstack_dir@ \ - @sql_union_dirs@ unittest storage plugin \ + @sql_union_dirs@ storage \ @sql_server@ @man_dirs@ tests \ netware @libmysqld_dirs@ \ mysql-test support-files sql-bench @tools_dirs@ \ @@ -208,6 +208,10 @@ test-bt-fast: -cd mysql-test ; MTR_BUILD_THREAD=auto \ @PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --force --comment=stress --suite=stress +test-bt-fast2: + -cd mysql-test ; MTR_BUILD_THREAD=auto \ + @PERL@ ./mysql-test-run.pl --force --comment=ps --ps-protocol --report-features + test-bt-debug: -cd mysql-test ; MTR_BUILD_THREAD=auto \ @PERL@ ./mysql-test-run.pl $(MTR_EXTRA_OPTIONS) --comment=debug --force --timer \ @@ -215,6 +219,8 @@ test-bt-debug: test-bt-debug-fast: +test-bt-debug-fast: + # Keep these for a while test-pl: test test-full-pl: test-full diff --git a/client/mysql.cc b/client/mysql.cc index fa03202f2d3..cc88b2ea6b9 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1281,21 +1281,35 @@ sig_handler handle_sigint(int sig) MYSQL *kill_mysql= NULL; /* terminate if no query being executed, or we already tried interrupting */ - if (!executing_query || interrupted_query) + /* terminate if no query being executed, or we already tried interrupting */ + if (!executing_query || (interrupted_query == 2)) + { + tee_fprintf(stdout, "Ctrl-C -- exit!\n"); goto err; + } kill_mysql= mysql_init(kill_mysql); if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password, "", opt_mysql_port, opt_mysql_unix_port,0)) + { + tee_fprintf(stdout, "Ctrl-C -- sorry, cannot connect to server to kill query, giving up ...\n"); goto err; + } + + interrupted_query++; + + /* mysqld < 5 does not understand KILL QUERY, skip to KILL CONNECTION */ + if ((interrupted_query == 1) && (mysql_get_server_version(&mysql) < 50000)) + interrupted_query= 2; /* kill_buffer is always big enough because max length of %lu is 15 */ - sprintf(kill_buffer, "KILL /*!50000 QUERY */ %lu", mysql_thread_id(&mysql)); - mysql_real_query(kill_mysql, kill_buffer, strlen(kill_buffer)); + sprintf(kill_buffer, "KILL %s%lu", + (interrupted_query == 1) ? "QUERY " : "", + mysql_thread_id(&mysql)); + tee_fprintf(stdout, "Ctrl-C -- sending \"%s\" to server ...\n", kill_buffer); + mysql_real_query(kill_mysql, kill_buffer, (uint) strlen(kill_buffer)); mysql_close(kill_mysql); - tee_fprintf(stdout, "Query aborted by Ctrl+C\n"); - - interrupted_query= 1; + tee_fprintf(stdout, "Ctrl-C -- query aborted.\n"); return; @@ -2873,7 +2887,7 @@ com_help(String *buffer __attribute__((unused)), "For developer information, including the MySQL Reference Manual, " "visit:\n" " http://dev.mysql.com/\n" - "To buy MySQL Network Support, training, or other products, visit:\n" + "To buy MySQL Enterprise support, training, or other products, visit:\n" " https://shop.mysql.com/\n", INFO_INFO); put_info("List of all MySQL commands:", INFO_INFO); if (!named_cmds) diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 61ff5f49dbf..3fb40cf28f1 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -54,6 +54,8 @@ static char **defaults_argv; static my_bool not_used; /* Can't use GET_BOOL without a value pointer */ +static my_bool opt_write_binlog; + #include <help_start.h> static struct my_option my_long_options[]= @@ -124,6 +126,11 @@ static struct my_option my_long_options[]= {"verbose", 'v', "Display more output about the process", (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"write-binlog", OPT_WRITE_BINLOG, + "All commands including mysqlcheck are binlogged. Enabled by default;" + "use --skip-write-binlog when commands should not be sent to replication slaves.", + (uchar**) &opt_write_binlog, (uchar**) &opt_write_binlog, 0, GET_BOOL, NO_ARG, + 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -448,6 +455,8 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, int ret; File fd; char query_file_path[FN_REFLEN]; + const uchar sql_log_bin[]= "SET SQL_LOG_BIN=0;"; + DBUG_ENTER("run_query"); DBUG_PRINT("enter", ("query: %s", query)); if ((fd= create_temp_file(query_file_path, opt_tmpdir, @@ -455,6 +464,22 @@ static int run_query(const char *query, DYNAMIC_STRING *ds_res, MYF(MY_WME))) < 0) die("Failed to create temporary file for defaults"); + /* + Master and slave should be upgraded separately. All statements executed + by mysql_upgrade will not be binlogged. + 'SET SQL_LOG_BIN=0' is executed before any other statements. + */ + if (!opt_write_binlog) + { + if (my_write(fd, sql_log_bin, sizeof(sql_log_bin)-1, + MYF(MY_FNABP | MY_WME))) + { + my_close(fd, MYF(0)); + my_delete(query_file_path, MYF(0)); + die("Failed to write to '%s'", query_file_path); + } + } + if (my_write(fd, (uchar*) query, strlen(query), MYF(MY_FNABP | MY_WME))) { @@ -647,6 +672,7 @@ static int run_mysqlcheck_upgrade(void) "--check-upgrade", "--all-databases", "--auto-repair", + opt_write_binlog ? "--write-binlog" : "--skip-write-binlog", NULL); } @@ -661,6 +687,7 @@ static int run_mysqlcheck_fixnames(void) "--all-databases", "--fix-db-names", "--fix-table-names", + opt_write_binlog ? "--write-binlog" : "--skip-write-binlog", NULL); } diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 82af7ca65f6..f55dc75df5d 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -78,6 +78,9 @@ static const char* host = 0; static int port= 0; static uint my_end_arg; static const char* sock= 0; +#ifdef HAVE_SMEM +static char *shared_memory_base_name= 0; +#endif static const char* user = 0; static char* pass = 0; static char *charset= 0; @@ -726,7 +729,10 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, switch (ev_type) { case QUERY_EVENT: - if (shall_skip_database(((Query_log_event*)ev)->db)) + if (strncmp(((Query_log_event*)ev)->query, "BEGIN", 5) && + strncmp(((Query_log_event*)ev)->query, "COMMIT", 6) && + strncmp(((Query_log_event*)ev)->query, "ROLLBACK", 8) && + shall_skip_database(((Query_log_event*)ev)->db)) goto end; if (opt_base64_output_mode == BASE64_OUTPUT_ALWAYS) { @@ -989,13 +995,13 @@ static struct my_option my_long_options[] = /* 'unspec' is not mentioned because it is just a placeholder. */ "Determine when the output statements should be base64-encoded BINLOG " "statements: 'never' disables it and works only for binlogs without " - "row-based events; 'auto' is the default and prints base64 only when " - "necessary (i.e., for row-based events and format description events); " - "'decode-rows' suppresses BINLOG statements for row events, but does " - "not exit as an error if a row event is found, unlike 'never'; " - "'always' prints base64 whenever possible. 'always' is for debugging " - "only and should not be used in a production system. The default is " - "'auto'. --base64-output is a short form for --base64-output=always." + "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." ,(uchar**) &opt_base64_output_mode_str, (uchar**) &opt_base64_output_mode_str, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, @@ -1074,6 +1080,12 @@ static struct my_option my_long_options[] = {"set-charset", OPT_SET_CHARSET, "Add 'SET NAMES character_set' to the output.", (uchar**) &charset, (uchar**) &charset, 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.", (uchar**) &shared_memory_base_name, + (uchar**) &shared_memory_base_name, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"short-form", 's', "Just show regular queries: no extra info and no " "row-based events. This is for testing only, and should not be used in " "production systems. If you want to suppress base64-output, consider " @@ -1376,6 +1388,11 @@ static Exit_status safe_connect() if (opt_protocol) mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char*) &opt_protocol); +#ifdef HAVE_SMEM + if (shared_memory_base_name) + mysql_options(mysql, MYSQL_SHARED_MEMORY_BASE_NAME, + shared_memory_base_name); +#endif if (!mysql_real_connect(mysql, host, user, pass, 0, port, sock, 0)) { error("Failed on connect: %s", mysql_error(mysql)); diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 82aabd77b24..1533e602639 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -652,6 +652,17 @@ static int use_db(char *database) return 0; } /* use_db */ +static int disable_binlog() +{ + const char *stmt= "SET SQL_LOG_BIN=0"; + if (mysql_query(sock, stmt)) + { + fprintf(stderr, "Failed to %s\n", stmt); + fprintf(stderr, "Error: %s\n", mysql_error(sock)); + return 1; + } + return 0; +} static int handle_request_for_tables(char *tables, uint length) { @@ -844,6 +855,14 @@ int main(int argc, char **argv) if (dbConnect(current_host, current_user, opt_password)) exit(EX_MYSQLERR); + 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)) { diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 92e9702aea0..ef38d760e5d 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (C) 2000-2006 MySQL AB, 2009 Sun Microsystems, Inc. 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 @@ -583,7 +583,7 @@ error: counter--; pthread_cond_signal(&count_threshhold); pthread_mutex_unlock(&counter_mutex); - my_thread_end(); + mysql_thread_end(); return 0; } diff --git a/client/mysqlslap.c b/client/mysqlslap.c index 2dba157dd78..5a36c712d91 100644 --- a/client/mysqlslap.c +++ b/client/mysqlslap.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 MySQL AB +/* Copyright (C) 2005 MySQL AB, 2009 Sun Microsystems, Inc. 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 @@ -423,6 +423,7 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) stats *sptr; conclusions conclusion; unsigned long long client_limit; + int sysret; head_sptr= (stats *)my_malloc(sizeof(stats) * iterations, MYF(MY_ZEROFILL|MY_FAE|MY_WME)); @@ -472,7 +473,10 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0")); if (pre_system) - if (system(pre_system)) { /* Ignore for now */ } + if ((sysret= system(pre_system)) != 0) + fprintf(stderr, + "Warning: Execution of pre_system option returned %d.\n", + sysret); /* Pre statements are always run after all other logic so they can @@ -487,8 +491,10 @@ void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr) run_statements(mysql, post_statements); if (post_system) - if (system(post_system)) { /* Ignore for now */ } - + if ((sysret= system(post_system)) != 0) + fprintf(stderr, + "Warning: Execution of post_system option returned %d.\n", + sysret); /* We are finished with this run */ if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary) drop_primary_key_list(); @@ -1942,7 +1948,7 @@ end: if (!opt_only_print) mysql_close(mysql); - my_thread_end(); + mysql_thread_end(); pthread_mutex_lock(&counter_mutex); thread_counter--; diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 0cd9cb3848d..217b6852656 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -82,6 +82,9 @@ enum { 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; static int opt_port= 0; @@ -429,6 +432,7 @@ static struct st_expected_errors saved_expected_errors; struct st_command { char *query, *query_buf,*first_argument,*last_argument,*end; + DYNAMIC_STRING content; int first_word_len, query_len; my_bool abort_on_error; struct st_expected_errors expected_errors; @@ -1152,6 +1156,8 @@ void free_used_memory() { struct st_command **q= dynamic_element(&q_lines, i, struct st_command**); my_free((*q)->query_buf,MYF(MY_ALLOW_ZERO_PTR)); + if ((*q)->content.str) + dynstr_free(&(*q)->content); my_free((*q),MYF(0)); } for (i= 0; i < 10; i++) @@ -1177,6 +1183,7 @@ void free_used_memory() mysql_server_end(); /* Don't use DBUG after mysql_server_end() */ + DBUG_VIOLATION_HELPER_LEAVE; return; } @@ -1543,7 +1550,7 @@ void show_diff(DYNAMIC_STRING* ds, else diff_name = 0; #else - diff_name = "diff"; // Otherwise always assume it's called diff + diff_name = "diff"; /* Otherwise always assume it's called diff */ #endif if (diff_name) @@ -3321,21 +3328,30 @@ void do_write_file_command(struct st_command *command, my_bool append) sizeof(write_file_args)/sizeof(struct command_arg), ' '); - /* If no delimiter was provided, use EOF */ - if (ds_delimiter.length == 0) - dynstr_set(&ds_delimiter, "EOF"); - if (!append && access(ds_filename.str, F_OK) == 0) { /* The file should not be overwritten */ die("File already exist: '%s'", ds_filename.str); } - init_dynamic_string(&ds_content, "", 1024, 1024); - read_until_delimiter(&ds_content, &ds_delimiter); - DBUG_PRINT("info", ("Writing to file: %s", ds_filename.str)); - str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append); - dynstr_free(&ds_content); + ds_content= command->content; + /* If it hasn't been done already by a loop iteration, fill it in */ + if (! ds_content.str) + { + /* If no delimiter was provided, use EOF */ + if (ds_delimiter.length == 0) + dynstr_set(&ds_delimiter, "EOF"); + + init_dynamic_string(&ds_content, "", 1024, 1024); + read_until_delimiter(&ds_content, &ds_delimiter); + command->content= ds_content; + } + /* This function could be called even if "false", so check before printing */ + if (cur_block->ok) + { + DBUG_PRINT("info", ("Writing to file: %s", ds_filename.str)); + str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append); + } dynstr_free(&ds_filename); dynstr_free(&ds_delimiter); DBUG_VOID_RETURN; @@ -3478,12 +3494,17 @@ void do_diff_files(struct st_command *command) die("command \"diff_files\" failed, file '%s' does not exist", ds_filename2.str); - if ((error= compare_files(ds_filename.str, ds_filename2.str))) + if ((error= compare_files(ds_filename.str, ds_filename2.str)) && + match_expected_error(command, error, NULL) < 0) { /* Compare of the two files failed, append them to output - so the failure can be analyzed + so the failure can be analyzed, but only if it was not + expected to fail. */ show_diff(&ds_res, ds_filename.str, ds_filename2.str); + log_file.write(&ds_res); + log_file.flush(); + dynstr_set(&ds_res, 0); } dynstr_free(&ds_filename); @@ -4910,6 +4931,8 @@ do_handle_error: <opts> - options to use for the connection * SSL - use SSL if available * COMPRESS - use compression if available + * SHM - use shared memory if available + * PIPE - use named pipe if available */ @@ -4918,6 +4941,7 @@ void do_connect(struct st_command *command) int con_port= opt_port; char *con_options; my_bool con_ssl= 0, con_compress= 0; + my_bool con_pipe= 0, con_shm= 0; struct st_connection* con_slot; static DYNAMIC_STRING ds_connection_name; @@ -4928,6 +4952,9 @@ void do_connect(struct st_command *command) static DYNAMIC_STRING ds_port; static DYNAMIC_STRING ds_sock; static DYNAMIC_STRING ds_options; +#ifdef HAVE_SMEM + static DYNAMIC_STRING ds_shm; +#endif const struct command_arg connect_args[] = { { "connection name", ARG_STRING, TRUE, &ds_connection_name, "Name of the connection" }, { "host", ARG_STRING, TRUE, &ds_host, "Host to connect to" }, @@ -4955,6 +4982,11 @@ void do_connect(struct st_command *command) die("Illegal argument for port: '%s'", ds_port.str); } +#ifdef HAVE_SMEM + /* Shared memory */ + init_dynamic_string(&ds_shm, ds_sock.str, 0, 0); +#endif + /* Sock */ if (ds_sock.length) { @@ -4993,6 +5025,10 @@ void do_connect(struct st_command *command) con_ssl= 1; else if (!strncmp(con_options, "COMPRESS", 8)) con_compress= 1; + else if (!strncmp(con_options, "PIPE", 4)) + con_pipe= 1; + else if (!strncmp(con_options, "SHM", 3)) + con_shm= 1; else die("Illegal option to connect: %.*s", (int) (end - con_options), con_options); @@ -5043,6 +5079,31 @@ void do_connect(struct st_command *command) } #endif +#ifdef __WIN__ + if (con_pipe) + { + uint protocol= MYSQL_PROTOCOL_PIPE; + mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, &protocol); + } +#endif + +#ifdef HAVE_SMEM + if (con_shm) + { + uint protocol= MYSQL_PROTOCOL_MEMORY; + if (!ds_shm.length) + die("Missing shared memory base name"); + mysql_options(&con_slot->mysql, MYSQL_SHARED_MEMORY_BASE_NAME, ds_shm.str); + mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, &protocol); + } + else if(shared_memory_base_name) + { + mysql_options(&con_slot->mysql, MYSQL_SHARED_MEMORY_BASE_NAME, + shared_memory_base_name); + } +#endif + + /* Use default db name */ if (ds_database.length == 0) dynstr_set(&ds_database, opt_db); @@ -5075,6 +5136,9 @@ void do_connect(struct st_command *command) dynstr_free(&ds_port); dynstr_free(&ds_sock); dynstr_free(&ds_options); +#ifdef HAVE_SMEM + dynstr_free(&ds_shm); +#endif DBUG_VOID_RETURN; } @@ -5746,6 +5810,12 @@ static struct my_option my_long_options[] = 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, + "Base name of shared memory.", (uchar**) &shared_memory_base_name, + (uchar**) &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.", (uchar**) &silent, (uchar**) &silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-safemalloc", OPT_SKIP_SAFEMALLOC, @@ -6809,8 +6879,10 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, MYSQL_STMT *stmt; DYNAMIC_STRING ds_prepare_warnings; DYNAMIC_STRING ds_execute_warnings; + ulonglong affected_rows; DBUG_ENTER("run_query_stmt"); DBUG_PRINT("query", ("'%-.60s'", query)); + LINT_INIT(affected_rows); /* Init a new stmt if it's not already one created for this connection @@ -6950,32 +7022,43 @@ void run_query_stmt(MYSQL *mysql, struct st_command *command, */ } - if (!disable_warnings) + /* + Need to grab affected rows information before getting + warnings here + */ { - /* Get the warnings from execute */ + ulonglong affected_rows; + LINT_INIT(affected_rows); + + if (!disable_info) + affected_rows= mysql_affected_rows(mysql); - /* Append warnings to ds - if there are any */ - if (append_warnings(&ds_execute_warnings, mysql) || - ds_execute_warnings.length || - ds_prepare_warnings.length || - ds_warnings->length) + if (!disable_warnings) { - dynstr_append_mem(ds, "Warnings:\n", 10); - if (ds_warnings->length) - dynstr_append_mem(ds, ds_warnings->str, - ds_warnings->length); - if (ds_prepare_warnings.length) - dynstr_append_mem(ds, ds_prepare_warnings.str, - ds_prepare_warnings.length); - if (ds_execute_warnings.length) - dynstr_append_mem(ds, ds_execute_warnings.str, - ds_execute_warnings.length); - } - } + /* Get the warnings from execute */ - if (!disable_info) - append_info(ds, mysql_affected_rows(mysql), mysql_info(mysql)); + /* Append warnings to ds - if there are any */ + if (append_warnings(&ds_execute_warnings, mysql) || + ds_execute_warnings.length || + ds_prepare_warnings.length || + ds_warnings->length) + { + dynstr_append_mem(ds, "Warnings:\n", 10); + if (ds_warnings->length) + dynstr_append_mem(ds, ds_warnings->str, + ds_warnings->length); + if (ds_prepare_warnings.length) + dynstr_append_mem(ds, ds_prepare_warnings.str, + ds_prepare_warnings.length); + if (ds_execute_warnings.length) + dynstr_append_mem(ds, ds_execute_warnings.str, + ds_execute_warnings.length); + } + } + if (!disable_info) + append_info(ds, affected_rows, mysql_info(mysql)); + } } end: @@ -7224,6 +7307,10 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) run_query_normal(cn, command, flags, query, query_len, ds, &ds_warnings); + dynstr_free(&ds_warnings); + if (command->type == Q_EVAL) + dynstr_free(&eval_query); + if (display_result_sorted) { /* Sort the result set and append it to result */ @@ -7254,11 +7341,8 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags) check_require(ds, command->require_file); } - dynstr_free(&ds_warnings); if (ds == &ds_result) dynstr_free(&ds_result); - if (command->type == Q_EVAL) - dynstr_free(&eval_query); DBUG_VOID_RETURN; } @@ -7704,6 +7788,11 @@ int main(int argc, char **argv) } #endif +#ifdef HAVE_SMEM + if (shared_memory_base_name) + mysql_options(&con->mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); +#endif + if (!(con->name = my_strdup("default", MYF(MY_WME)))) die("Out of memory"); @@ -7742,7 +7831,32 @@ int main(int argc, char **argv) command->type= Q_COMMENT; } - if (cur_block->ok) + my_bool ok_to_do= cur_block->ok; + /* + Some commands need to be "done" the first time if they may get + re-iterated over in a true context. This can only happen if there's + a while loop at some level above the current block. + */ + if (!ok_to_do) + { + if (command->type == Q_SOURCE || + command->type == Q_ERROR || + command->type == Q_WRITE_FILE || + command->type == Q_APPEND_FILE || + command->type == Q_PERL) + { + for (struct st_block *stb= cur_block-1; stb >= block_stack; stb--) + { + if (stb->cmd == cmd_while) + { + ok_to_do= 1; + break; + } + } + } + } + + if (ok_to_do) { command->last_argument= command->first_argument; processed = 1; @@ -8053,6 +8167,8 @@ int main(int argc, char **argv) if (parsing_disabled) die("Test ended with parsing disabled"); + my_bool empty_result= FALSE; + /* The whole test has been executed _sucessfully_. Time to compare result or save it to record file. @@ -8093,11 +8209,20 @@ int main(int argc, char **argv) } else { - die("The test didn't produce any output"); + /* Empty output is an error *unless* we also have an empty result file */ + if (! result_file_name || record || + compare_files (log_file.file_name(), result_file_name)) + { + die("The test didn't produce any output"); + } + else + { + empty_result= TRUE; /* Meaning empty was expected */ + } } - if (!command_executed && result_file_name) - die("No queries executed but result file found!"); + if (!command_executed && result_file_name && !empty_result) + die("No queries executed but non-empty result file found!"); verbose_msg("Test has succeeded!"); timer_output(); @@ -8184,6 +8309,8 @@ void do_get_replace_column(struct st_command *command) } my_free(start, MYF(0)); command->last_argument= command->end; + + DBUG_VOID_RETURN; } diff --git a/cmd-line-utils/readline/display.c b/cmd-line-utils/readline/display.c index 720ef3a82e4..e0f24b2488b 100644 --- a/cmd-line-utils/readline/display.c +++ b/cmd-line-utils/readline/display.c @@ -463,10 +463,10 @@ rl_redisplay () int newlines, lpos, temp, modmark; char *prompt_this_line; #if defined (HANDLE_MULTIBYTE) - int num, n0; + int num, n0= 0; wchar_t wc; size_t wc_bytes; - int wc_width; + int wc_width= 0; mbstate_t ps; int _rl_wrapped_multicolumn = 0; #endif @@ -824,7 +824,7 @@ rl_redisplay () cpos_buffer_position = out; lb_linenum = newlines; } - for (i = in; i < in+wc_bytes; i++) + for (i = in; i < in+(int)wc_bytes; i++) line[out++] = rl_line_buffer[i]; for (i = 0; i < wc_width; i++) CHECK_LPOS(); diff --git a/configure.in b/configure.in index 0bbb91894c8..a0ca2c40059 100644 --- a/configure.in +++ b/configure.in @@ -15,7 +15,7 @@ AC_CANONICAL_SYSTEM # MySQL version number. # # Note: the following line must be parseable by win/configure.js:GetVersion() -AM_INIT_AUTOMAKE(mysql, 5.1.38-maria-beta) +AM_INIT_AUTOMAKE(mysql, 5.1.41-mariadb-beta) AM_CONFIG_HEADER([include/config.h:config.h.in]) PROTOCOL_VERSION=10 @@ -1652,13 +1652,14 @@ then DEBUG_OPTIMIZE_CXX="-O" OPTIMIZE_CXXFLAGS="$MAX_CXX_OPTIMIZE" else - DEBUG_CXXFLAGS="-g" DEBUG_OPTIMIZE_CXX="" case $SYSTEM_TYPE in *solaris*) + DEBUG_CXXFLAGS="-g0" OPTIMIZE_CXXFLAGS="-O1" ;; *) + DEBUG_CXXFLAGS="-g" OPTIMIZE_CXXFLAGS="-O" ;; esac @@ -1715,6 +1716,23 @@ else CXXFLAGS="$OPTIMIZE_CXXFLAGS $CXXFLAGS" fi +# Debug Sync Facility. NOTE: depends on 'with_debug'. Must be behind it. +AC_MSG_CHECKING(if Debug Sync Facility should be enabled.) +AC_ARG_ENABLE(debug_sync, + AS_HELP_STRING([--enable-debug-sync], + [Build a version with Debug Sync Facility]), + [ enable_debug_sync=$enableval ], + [ enable_debug_sync=$with_debug ]) + +if test "$enable_debug_sync" != "no" +then + AC_DEFINE([ENABLED_DEBUG_SYNC], [1], + [If Debug Sync Facility should be enabled]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + # If we should allow error injection tests AC_ARG_WITH(error-inject, AC_HELP_STRING([--with-error-inject],[Enable error injection in MySQL Server]), @@ -2775,7 +2793,7 @@ server_scripts= dnl This probably should be cleaned up more - for now the threaded dnl client is just using plain-old libs. -sql_client_dirs="strings regex mysys libmysql" +sql_client_dirs="strings mysys dbug extra regex libmysql unittest" AM_CONDITIONAL(THREAD_SAFE_CLIENT, test "$THREAD_SAFE_CLIENT" != "no") @@ -2803,12 +2821,20 @@ fi AC_SUBST(netware_dir) AM_CONDITIONAL(HAVE_NETWARE, test "$netware_dir" = "netware") -if test "$with_server" = "yes" -o "$THREAD_SAFE_CLIENT" != "no" +if test "$with_server" != "no" -o "$THREAD_SAFE_CLIENT" != "no" then AC_DEFINE([THREAD], [1], [Define if you want to have threaded code. This may be undef on client code]) + # Avoid _PROGRAMS names + THREAD_LOBJECTS="thr_alarm.o thr_lock.o thr_mutex.o thr_rwlock.o my_pthread.o my_thr_init.o mf_keycache.o mf_keycaches.o waiting_threads.o" + AC_SUBST(THREAD_LOBJECTS) +fi +AM_CONDITIONAL(NEED_THREAD, test "$with_server" != "no" -o "$THREAD_SAFE_CLIENT" != "no") + +if test "$with_server" != "no" +then server_scripts="mysqld_safe mysql_install_db" - sql_server_dirs="strings mysys dbug extra regex" + sql_server_dirs="strings mysys dbug extra regex storage plugin" sql_server="vio sql" fi @@ -2834,9 +2860,10 @@ AC_SUBST(mysql_plugin_defs) # Now that sql_client_dirs and sql_server_dirs are stable, determine the union. -# Start with the (longer) server list, add each client item not yet present. -sql_union_dirs=" $sql_server_dirs " -for DIR in $sql_client_dirs +# We support client-only builds by "--without-server", but not vice versa, +# so we start with the client list, then add each server item not yet present. +sql_union_dirs=" $sql_client_dirs " +for DIR in $sql_server_dirs do if echo " $sql_union_dirs " | grep " $DIR " >/dev/null then diff --git a/extra/yassl/include/yassl_int.hpp b/extra/yassl/include/yassl_int.hpp index 12489468e6b..1e761f559e2 100644 --- a/extra/yassl/include/yassl_int.hpp +++ b/extra/yassl/include/yassl_int.hpp @@ -441,7 +441,7 @@ public: const Ciphers& GetCiphers() const; const DH_Parms& GetDH_Parms() const; const Stats& GetStats() const; - VerifyCallback getVerifyCallback() const; + VerifyCallback getVerifyCallback() const; pem_password_cb GetPasswordCb() const; void* GetUserData() const; bool GetSessionCacheOff() const; diff --git a/extra/yassl/taocrypt/src/random.cpp b/extra/yassl/taocrypt/src/random.cpp index 89fd5f7c7bc..2bbc0a85e8b 100644 --- a/extra/yassl/taocrypt/src/random.cpp +++ b/extra/yassl/taocrypt/src/random.cpp @@ -27,7 +27,6 @@ #include <time.h> #if defined(_WIN32) - #define _WIN32_WINNT 0x0400 #include <windows.h> #include <wincrypt.h> #else diff --git a/include/my_dbug.h b/include/my_dbug.h index 5c185d5eef2..109a1a4eb19 100644 --- a/include/my_dbug.h +++ b/include/my_dbug.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (C) 2000 MySQL AB & 2009 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 @@ -16,7 +16,30 @@ #ifndef _dbug_h #define _dbug_h -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(DBUG_OFF) +class Dbug_violation_helper +{ +public: + inline Dbug_violation_helper() : + _entered(TRUE) + { } + + inline ~Dbug_violation_helper() + { + assert(!_entered); + } + + inline void leave() + { + _entered= FALSE; + } + +private: + bool _entered; +}; +#endif /* C++ */ + +#ifdef __cplusplus extern "C" { #endif #if !defined(DBUG_OFF) && !defined(_lint) @@ -30,34 +53,51 @@ struct _db_stack_frame_ { struct _db_code_state_; extern my_bool _dbug_on_; -extern my_bool _db_keyword_(struct _db_code_state_ *, const char *, int); +extern my_bool _db_keyword_(struct _db_code_state_ *cs, const char *keyword, + int strict_flag); +extern int _db_strict_keyword_(const char *keyword); extern int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len); extern int _db_explain_init_(char *buf, size_t len); extern int _db_is_pushed_(void); extern void _db_setjmp_(void); extern void _db_longjmp_(void); extern void _db_process_(const char *name); -extern void _db_push_(const char *control); -extern void _db_pop_(void); +extern void _db_push_(const char *control); +extern void _db_pop_(void); extern void _db_set_(const char *control); extern void _db_set_init_(const char *control); -extern void _db_enter_(const char *_func_, const char *_file_, uint _line_, - struct _db_stack_frame_ *_stack_frame_); +extern void _db_enter_(const char *_func_, const char *_file_, uint _line_, + struct _db_stack_frame_ *_stack_frame_); extern void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_); extern void _db_pargs_(uint _line_,const char *keyword); extern void _db_doprnt_ _VARARGS((const char *format,...)) ATTRIBUTE_FORMAT(printf, 1, 2); -extern void _db_dump_(uint _line_,const char *keyword, +extern void _db_dump_(uint _line_,const char *keyword, const unsigned char *memory, size_t length); -extern void _db_end_(void); -extern void _db_lock_file_(void); -extern void _db_unlock_file_(void); -extern FILE *_db_fp_(void); +extern void _db_end_(void); +extern void _db_lock_file_(void); +extern void _db_unlock_file_(void); +extern FILE *_db_fp_(void); extern void _db_flush_(); +#ifdef __cplusplus + #define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_; \ + Dbug_violation_helper dbug_violation_helper; \ _db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_) -#define DBUG_LEAVE _db_return_ (__LINE__, &_db_stack_frame_) +#define DBUG_VIOLATION_HELPER_LEAVE dbug_violation_helper.leave() + +#else /* C */ + +#define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_; \ + _db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_) +#define DBUG_VIOLATION_HELPER_LEAVE do { } while(0) + +#endif /* C++ */ + +#define DBUG_LEAVE \ + DBUG_VIOLATION_HELPER_LEAVE; \ + _db_return_ (__LINE__, &_db_stack_frame_) #define DBUG_RETURN(a1) do {DBUG_LEAVE; return(a1);} while(0) #define DBUG_VOID_RETURN do {DBUG_LEAVE; return;} while(0) #define DBUG_EXECUTE(keyword,a1) \ @@ -88,28 +128,15 @@ extern void _db_flush_(); #define DEBUGGER_OFF do { _dbug_on_= 0; } while(0) #define DEBUGGER_ON do { _dbug_on_= 1; } while(0) #define IF_DBUG(A) A -#ifndef __WIN__ #define DBUG_ABORT() (_db_flush_(), abort()) -#else -/* - Avoid popup with abort/retry/ignore buttons. When BUG#31745 is fixed we can - call abort() instead of _exit(3) (now it would cause a "test signal" popup). -*/ -#include <crtdbg.h> -#define DBUG_ABORT() (_db_flush_(),\ - (void)_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE),\ - (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR),\ - _exit(3)) -#endif - #else /* No debugger */ #define DBUG_ENTER(a1) #define DBUG_LEAVE -#define DBUG_RETURN(a1) do { return(a1); } while(0) -#define DBUG_VOID_RETURN do { return; } while(0) -#define DBUG_EXECUTE(keyword,a1) do { } while(0) -#define DBUG_EXECUTE_IF(keyword,a1) do { } while(0) +#define DBUG_RETURN(a1) do { return(a1); } while(0) +#define DBUG_VOID_RETURN do { return; } while(0) +#define DBUG_EXECUTE(keyword,a1) do { } while(0) +#define DBUG_EXECUTE_IF(keyword,a1) do { } while(0) #define DBUG_EVALUATE(keyword,a1,a2) (a2) #define DBUG_EVALUATE_IF(keyword,a1,a2) (a2) #define DBUG_PRINT(keyword,arglist) do { } while(0) diff --git a/include/my_sys.h b/include/my_sys.h index 315454062f1..fcd319d3e95 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -69,6 +69,7 @@ extern int NEAR my_errno; /* Last error in mysys */ #define MY_HOLD_ON_ERROR 256 /* my_realloc() ; Return old ptr on error */ #define MY_DONT_OVERWRITE_FILE 2048 /* my_copy: Don't overwrite file */ #define MY_THREADSAFE 2048 /* my_seek(): lock fd mutex */ +#define MY_SYNC 4096 /* my_copy(): sync dst file */ #define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */ #define MY_GIVE_INFO 2 /* Give time info about process*/ @@ -175,6 +176,16 @@ extern char *my_strndup(const char *from, size_t length, #define TRASH(A,B) /* nothing */ #endif +#if defined(ENABLED_DEBUG_SYNC) +extern void (*debug_sync_C_callback_ptr)(const char *, size_t); +#define DEBUG_SYNC_C(_sync_point_name_) do { \ + if (debug_sync_C_callback_ptr != NULL) \ + (*debug_sync_C_callback_ptr)(STRING_WITH_LEN(_sync_point_name_)); } \ + while(0) +#else +#define DEBUG_SYNC_C(_sync_point_name_) +#endif /* defined(ENABLED_DEBUG_SYNC) */ + #ifdef HAVE_LARGE_PAGES extern uint my_get_large_page_size(void); extern uchar * my_large_malloc(size_t size, myf my_flags); @@ -727,7 +738,6 @@ extern int wild_compare(const char *str,const char *wildstr, extern WF_PACK *wf_comp(char * str); extern int wf_test(struct wild_file_pack *wf_pack,const char *name); extern void wf_end(struct wild_file_pack *buffer); -extern size_t strip_sp(char * str); extern my_bool array_append_string_unique(const char *str, const char **array, size_t size); extern void get_date(char * to,int timeflag,time_t use_time); diff --git a/include/myisamchk.h b/include/myisamchk.h index 6d2d887cf68..057c06652a1 100644 --- a/include/myisamchk.h +++ b/include/myisamchk.h @@ -154,6 +154,10 @@ typedef struct st_handler_check_param char temp_filename[FN_REFLEN]; IO_CACHE read_cache; enum_handler_stats_method stats_method; +#ifdef THREAD + pthread_mutex_t print_msg_mutex; + my_bool need_print_msg_lock; +#endif } HA_CHECK; diff --git a/include/mysql.h b/include/mysql.h index 074098aef1b..b4b399eccc1 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -558,6 +558,16 @@ unsigned long STDCALL mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); void STDCALL mysql_debug(const char *debug); +char * STDCALL mysql_odbc_escape_string(MYSQL *mysql, + char *to, + unsigned long to_length, + const char *from, + unsigned long from_length, + void *param, + char * + (*extend_buffer) + (void *, char *to, + unsigned long *length)); void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name); unsigned int STDCALL mysql_thread_safe(void); my_bool STDCALL mysql_embedded(void); diff --git a/include/mysql.h.pp b/include/mysql.h.pp index c333cb2bec5..c6a64ccb96e 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -518,6 +518,16 @@ unsigned long mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, unsigned long length); void mysql_debug(const char *debug); +char * mysql_odbc_escape_string(MYSQL *mysql, + char *to, + unsigned long to_length, + const char *from, + unsigned long from_length, + void *param, + char * + (*extend_buffer) + (void *, char *to, + unsigned long *length)); void myodbc_remove_escape(MYSQL *mysql,char *name); unsigned int mysql_thread_safe(void); my_bool mysql_embedded(void); diff --git a/include/violite.h b/include/violite.h index 7f017635f31..9d104a0b23f 100644 --- a/include/violite.h +++ b/include/violite.h @@ -44,7 +44,7 @@ enum enum_vio_type Vio* vio_new(my_socket sd, enum enum_vio_type type, uint flags); #ifdef __WIN__ Vio* vio_new_win32pipe(HANDLE hPipe); -Vio* vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, +Vio* vio_new_win32shared_memory(HANDLE handle_file_map, HANDLE handle_map, HANDLE event_server_wrote, HANDLE event_server_read, @@ -222,7 +222,11 @@ struct st_vio HANDLE event_conn_closed; size_t shared_memory_remain; char *shared_memory_pos; - NET *net; #endif /* HAVE_SMEM */ +#ifdef _WIN32 + OVERLAPPED pipe_overlapped; + DWORD read_timeout_millis; + DWORD write_timeout_millis; +#endif }; #endif /* vio_violite_h_ */ diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 59406ecff09..b44d578f821 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1642,6 +1642,20 @@ mysql_real_escape_string(MYSQL *mysql, char *to,const char *from, return (uint) escape_string_for_mysql(mysql->charset, to, 0, from, length); } + +char * STDCALL +mysql_odbc_escape_string(MYSQL *mysql __attribute__((unused)), + char *to __attribute__((unused)), + ulong to_length __attribute__((unused)), + const char *from __attribute__((unused)), + ulong from_length __attribute__((unused)), + void *param __attribute__((unused)), + char * (*extend_buffer)(void *, char *, ulong *) + __attribute__((unused))) +{ + return NULL; +} + void STDCALL myodbc_remove_escape(MYSQL *mysql,char *name) { diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 45e85b15120..5c05bff8242 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -78,6 +78,7 @@ EXPORTS mysql_next_result mysql_num_fields mysql_num_rows + mysql_odbc_escape_string mysql_options mysql_stmt_param_count mysql_stmt_param_metadata diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index f69f6d26c6d..7d2abb64065 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -90,8 +90,10 @@ ENDFOREACH(rpath) FOREACH (ENGINE_LIB ${MYSQLD_STATIC_ENGINE_LIBS}) INCLUDE(${CMAKE_SOURCE_DIR}/storage/${plugin_dir_${ENGINE_LIB}}/CMakeLists.txt) STRING(TOUPPER ${ENGINE_LIB} ENGINE_LIB_UPPER) + SET(ENGINE_DIR ${${ENGINE_LIB_UPPER}_DIR}) + INCLUDE(${CMAKE_SOURCE_DIR}/storage/${ENGINE_DIR}/CMakeLists.txt) FOREACH(rpath ${${ENGINE_LIB_UPPER}_SOURCES}) - SET(LIB_SOURCES ${LIB_SOURCES} ${CMAKE_SOURCE_DIR}/storage/${plugin_dir_${ENGINE_LIB}}/${rpath}) + SET(LIB_SOURCES ${LIB_SOURCES} ${CMAKE_SOURCE_DIR}/storage/${ENGINE_DIR}/${rpath}) ENDFOREACH(rpath) ENDFOREACH(ENGINE_LIB) @@ -127,6 +129,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/sql_list.cc ../sql/sql_load.cc ../sql/sql_locale.cc ../sql/sql_binlog.cc ../sql/sql_manager.cc ../sql/sql_map.cc ../sql/sql_parse.cc ../sql/sql_partition.cc ../sql/sql_plugin.cc + ../sql/debug_sync.cc ../sql/sql_prepare.cc ../sql/sql_rename.cc ../sql/sql_repl.cc ../sql/sql_select.cc ../sql/sql_servers.cc ../sql/sql_show.cc ../sql/sql_state.c ../sql/sql_string.cc @@ -152,6 +155,14 @@ ADD_LIBRARY(mysqlserver STATIC ${LIBMYSQLD_SOURCES}) ADD_DEPENDENCIES(mysqlserver GenServerSource GenError) TARGET_LINK_LIBRARIES(mysqlserver) +# Add any additional libraries requested by engine(s) +FOREACH (ENGINE_LIB ${MYSQLD_STATIC_ENGINE_LIBS}) + STRING(TOUPPER ${ENGINE_LIB} ENGINE_LIB_UPPER) + IF(${ENGINE_LIB_UPPER}_LIBS) + TARGET_LINK_LIBRARIES(mysqlserver ${${ENGINE_LIB_UPPER}_LIBS}) + ENDIF(${ENGINE_LIB_UPPER}_LIBS) +ENDFOREACH(ENGINE_LIB) + ADD_LIBRARY(libmysqld SHARED cmake_dummy.c libmysqld.def) ADD_DEPENDENCIES(libmysqld mysqlserver) TARGET_LINK_LIBRARIES(libmysqld mysqlserver wsock32) diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index ecf45a23399..f5da13b145b 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -74,6 +74,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \ parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \ rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \ + debug_sync.cc \ sql_tablespace.cc \ rpl_injector.cc my_user.c partition_info.cc \ sql_servers.cc event_parse_data.cc opt_table_elimination.cc diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 2622ae6988f..7de1ecd6ef3 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -142,6 +142,8 @@ emb_advanced_command(MYSQL *mysql, enum enum_server_command command, if (!skip_check) result= thd->is_error() ? -1 : 0; + thd->mysys_var= 0; + #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.finish_current_query(); #endif @@ -634,6 +636,7 @@ void *create_embedded_thd(int client_flag) thread_count++; threads.append(thd); + thd->mysys_var= 0; return thd; err: delete(thd); diff --git a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c index aff9391e015..0c20b35236d 100644 --- a/libmysqld/libmysqld.c +++ b/libmysqld/libmysqld.c @@ -164,6 +164,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, port=0; unix_socket=0; + client_flag|=mysql->options.client_flag; /* Send client information for access check */ client_flag|=CLIENT_CAPABILITIES; if (client_flag & CLIENT_MULTI_STATEMENTS) diff --git a/libmysqld/libmysqld.def b/libmysqld/libmysqld.def index 754aa6b3c29..ed9ff2a6600 100644 --- a/libmysqld/libmysqld.def +++ b/libmysqld/libmysqld.def @@ -50,6 +50,7 @@ EXPORTS mysql_next_result mysql_num_fields mysql_num_rows + mysql_odbc_escape_string mysql_options mysql_ping mysql_query diff --git a/mysql-test/collections/README.experimental b/mysql-test/collections/README.experimental index 9eee2394423..2f5ee7b00ab 100644 --- a/mysql-test/collections/README.experimental +++ b/mysql-test/collections/README.experimental @@ -23,3 +23,10 @@ The syntax is as follows: start with the same characters up to the last letter before the asterisk are considered experimental: main.a* # get rid of main.alias, main.alibaba and main.agliolio + +6) Optionally, the test case may be followed by one or more platform + qualifiers beginning with @ or @!. The test will then be considered + experimental only/except on that platform. Basic OS names as + reported by $^O in Perl, or 'windows' are supported, this includes + solaris, linux, windows, aix, darwin, ... Example: + main.alias @aix @windows # Fails on those diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental index 8bec38a373b..a0fa2a30a69 100644 --- a/mysql-test/collections/default.experimental +++ b/mysql-test/collections/default.experimental @@ -1,6 +1,45 @@ +# For easier human reading (MTR doesn't care), please keep entries +# in alphabetical order. This also helps with merge conflict resolution. + +binlog.binlog_multi_engine # joro : NDB tests marked as experimental as agreed with bochklin + funcs_1.charset_collation_1 # depends on compile-time decisions -binlog.binlog_tmp_table # Bug#45578: Test binlog_tmp_table fails ramdonly on PB2: Unknown table 't2' -main.ctype_gbk_binlog # Bug#46010: main.ctype_gbk_binlog fails sporadically : Table 't2' already exists -rpl.rpl_row_create_table # Bug#45576: rpl_row_create_table fails on PB2 +funcs_1.is_cml_ndb # joro : NDB tests marked as experimental as agreed with bochklin +funcs_1.is_columns_ndb # joro : NDB tests marked as experimental as agreed with bochklin +funcs_1.is_engines_ndb # joro : NDB tests marked as experimental as agreed with bochklin +funcs_1.is_tables_ndb # joro : NDB tests marked as experimental as agreed with bochklin +funcs_1.ndb* # joro : NDB tests marked as experimental as agreed with bochklin + +funcs_2.ndb_charset # joro : NDB tests marked as experimental as agreed with bochklin + +main.ctype_gbk_binlog @solaris # Bug#46010: main.ctype_gbk_binlog fails sporadically : Table 't2' already exists +main.innodb-autoinc* # Bug#47809 2009-10-04 joro innodb-autoinc.test fails with valgrind errors with the innodb plugin +main.plugin_load @solaris # Bug#42144 + +ndb.* # joro : NDB tests marked as experimental as agreed with bochklin + +rpl.rpl_cross_version* # Bug #43913 2009-10-26 joro rpl_cross_version can't pass on conflicts complainig clash with --slave-load-tm +rpl.rpl_get_master_version_and_clock* # Bug#46931 2009-08-26 alik rpl.rpl_get_master_version_and_clock fails on hpux11.31 +rpl.rpl_innodb_bug28430* @solaris # Bug#46029 +rpl.rpl_row_create_table* # Bug#45576: rpl_row_create_table fails on PB2 +rpl.rpl_trigger* # Bug#47810 2009-10-04 joro rpl.rpl_trigger.test fails with valgrind errors with the innodb plugin + +rpl_ndb.* # joro : NDB tests marked as experimental as agreed with bochklin rpl_ndb.rpl_ndb_log # Bug#38998 -rpl.rpl_innodb_bug28430 # Bug#46029 + +stress.ddl_ndb # joro : NDB tests marked as experimental as agreed with bochklin + +parts.ndb_dd_backuprestore # joro : NDB tests marked as experimental as agreed with bochklin +parts.part_supported_sql_func_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_alter1_1_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_alter1_1_2_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_alter1_2_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_auto_increment_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_basic_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_engine_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_int_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_mgm_lc0_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_mgm_lc1_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_mgm_lc2_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_syntax_ndb # joro : NDB tests marked as experimental as agreed with bochklin +parts.partition_value_ndb # joro : NDB tests marked as experimental as agreed with bochklin diff --git a/mysql-test/extra/binlog_tests/binlog.test b/mysql-test/extra/binlog_tests/binlog.test index 5d898d41a54..b819996acb0 100644 --- a/mysql-test/extra/binlog_tests/binlog.test +++ b/mysql-test/extra/binlog_tests/binlog.test @@ -270,3 +270,42 @@ INSERT INTO test.t1 VALUES (1), (2); CREATE TABLE test.t2 SELECT * FROM test.t1; USE test; DROP TABLES t1, t2; + +# +# Bug#46640 +# This test verifies if the server_id stored in the "format +# description BINLOG statement" will override the server_id +# of the server executing the statements. +# + +connect (fresh,localhost,root,,test); +connection fresh; + +RESET MASTER; +CREATE TABLE t1 (a INT PRIMARY KEY); + +# Format description event, with server_id = 10; +BINLOG ' +3u9kSA8KAAAAZgAAAGoAAAABAAQANS4xLjM1LW1hcmlhLWJldGExLWRlYnVnLWxvZwAAAAAAAAAA +AAAAAAAAAAAAAAAAAADe72RIEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC +'; + +# What server_id is logged for a statement? Should be our own, not the +# one from the format description event. +INSERT INTO t1 VALUES (1); + +# INSERT INTO t1 VALUES (2), with server_id=20. Check that this is logged +# with our own server id, not the 20 from the BINLOG statement. +BINLOG ' +3u9kSBMUAAAAKQAAAJEBAAAAABoAAAAAAAAABHRlc3QAAnQxAAEDAAA= +3u9kSBcUAAAAIgAAALMBAAAQABoAAAAAAAEAAf/+AgAAAA== +'; + +# Show binlog events to check that server ids are correct. +--replace_column 1 # 2 # 5 # +--replace_regex /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ +SHOW BINLOG EVENTS; + +DROP TABLE t1; +disconnect fresh; + diff --git a/mysql-test/extra/binlog_tests/binlog_failure_mixing_engines.test b/mysql-test/extra/binlog_tests/binlog_failure_mixing_engines.test new file mode 100644 index 00000000000..54f3c538c79 --- /dev/null +++ b/mysql-test/extra/binlog_tests/binlog_failure_mixing_engines.test @@ -0,0 +1,300 @@ +################################################################################ +# Let +# - B be begin, C commit and R rollback. +# - T a statement that accesses and changes only transactional tables, i.e. +# T-tables +# - N a statement that accesses and changes only non-transactional tables, +# i.e, N-tables. +# - M be a mixed statement, i.e. a statement that updates both T- and +# N-tables. +# - M* be a mixed statement that fails while updating either a T +# or N-table. +# - N* be a statement that fails while updating a N-table. +# +# In this test case, when changes are logged as rows either in the RBR or MIXED +# modes, we check if a M* statement that happens early in a transaction is +# written to the binary log outside the boundaries of the transaction and +# wrapped up in a BEGIN/ROLLBACK. This is done to keep the slave consistent with +# the master as the rollback will keep the changes on N-tables and undo them on +# T-tables. In particular, we expect the following behavior: +# +# 1. B M* T C would generate in the binlog B M* R B T C. +# 2. B M M* C would generate in the binlog B M M* C. +# 3. B M* M* T C would generate in the binlog B M* R B M* R B T C. +# +# SBR is not considered in this test because a failing statement is written to +# the binary along with the error code such that a slave executes and rolls it +# back, thus undoing the effects on T-tables. +# +# Note that, in the first case, we are not preserving history from the master as +# we are introducing a rollback that never happened. However, this seems to be +# more acceptable than making the slave diverge. In the second case, the slave +# will diverge as the changes on T-tables that originated from the M statement +# are rolled back on the master but not on the slave. Unfortunately, we cannot +# simply roll the transaction back as this would undo any uncommitted changes +# on T-tables. +# +# We check two more cases. First, INSERT...SELECT* which produces the following +# results: +# +# 1. B T INSERT M...SELECT* C" with an error in INSERT M...SELECT* generates in +# the binlog the following entries: "Nothing". +# 2. B INSERT M...SELECT* C" with an error in INSERT M...SELECT* generates in +# the binlog the following entries: B INSERT M...SELECT* R. +# +# Finally, we also check if any N statement that happens early in a transaction +# (i.e. before any T or M statement) is written to the binary log outside the +# boundaries of the transaction. In particular, we expect the following +# behavior: +# +# 1. B N N T C would generate in the binlog B N C B N C B T C. +# 2. B N N T R would generate in the binlog B N C B N C B T R. +# 3. B N* N* T C would generate in the binlog B N R B N R B T C. +# 4. B N* N* T R would generate in the binlog B N R B N R B T R. +# 5. B N N T N T C would generate in the binlog B N C B N C B T N T C. +# 6. B N N T N T R would generate in the binlog the B N C B N C B T N T R. +# +# Such issues do not happen in SBR. In RBR and MBR, a full-fledged fix will be +# pushed after the WL#2687. +# +# Please, remove this test case after pushing WL#2687. +################################################################################ + + +--echo ################################################################################### +--echo # CONFIGURATION +--echo ################################################################################### +CREATE TABLE nt_1 (a text, b int PRIMARY KEY) ENGINE = MyISAM; +CREATE TABLE nt_2 (a text, b int PRIMARY KEY) ENGINE = MyISAM; +CREATE TABLE tt_1 (a text, b int PRIMARY KEY) ENGINE = Innodb; +CREATE TABLE tt_2 (a text, b int PRIMARY KEY) ENGINE = Innodb; + +DELIMITER |; + +CREATE TRIGGER tr_i_tt_1_to_nt_1 BEFORE INSERT ON tt_1 FOR EACH ROW +BEGIN + INSERT INTO nt_1 VALUES (NEW.a, NEW.b); +END| + +CREATE TRIGGER tr_i_nt_2_to_tt_2 BEFORE INSERT ON nt_2 FOR EACH ROW +BEGIN + INSERT INTO tt_2 VALUES (NEW.a, NEW.b); +END| + +DELIMITER ;| + +--echo ################################################################################### +--echo # CHECK HISTORY IN BINLOG +--echo ################################################################################### +--echo +--echo +--echo +--echo *** "B M* T C" with error in M* generates in the binlog the "B M* R B T C" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +INSERT INTO nt_1 VALUES ("new text 1", 1); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO tt_1 VALUES (USER(), 2), (USER(), 1); +INSERT INTO tt_2 VALUES ("new text 3", 3); +COMMIT; +--source include/show_binlog_events.inc + +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +INSERT INTO tt_2 VALUES ("new text 4", 4); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO nt_2 VALUES (USER(), 5), (USER(), 4); +INSERT INTO tt_2 VALUES ("new text 6", 6); +COMMIT; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B M M* T C" with error in M* generates in the binlog the "B M M* T C" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +INSERT INTO nt_1 VALUES ("new text 10", 10); +BEGIN; +INSERT INTO tt_1 VALUES ("new text 7", 7), ("new text 8", 8); +--error ER_DUP_ENTRY +INSERT INTO tt_1 VALUES (USER(), 9), (USER(), 10); +INSERT INTO tt_2 VALUES ("new text 11", 11); +COMMIT; +--source include/show_binlog_events.inc + +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +INSERT INTO tt_2 VALUES ("new text 15", 15); +BEGIN; +INSERT INTO nt_2 VALUES ("new text 12", 12), ("new text 13", 13); +--error ER_DUP_ENTRY +INSERT INTO nt_2 VALUES (USER(), 14), (USER(), 15); +INSERT INTO tt_2 VALUES ("new text 16", 16); +COMMIT; +--source include/show_binlog_events.inc + + +--echo +--echo +--echo +--echo *** "B M* M* T C" with error in M* generates in the binlog the "B M* R B M* R B T C" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +INSERT INTO nt_1 VALUES ("new text 18", 18); +INSERT INTO nt_1 VALUES ("new text 20", 20); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO tt_1 VALUES (USER(), 17), (USER(), 18); +--error ER_DUP_ENTRY +INSERT INTO tt_1 VALUES (USER(), 19), (USER(), 20); +INSERT INTO tt_2 VALUES ("new text 21", 21); +COMMIT; +--source include/show_binlog_events.inc + +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +INSERT INTO tt_2 VALUES ("new text 23", 23); +INSERT INTO tt_2 VALUES ("new text 25", 25); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO nt_2 VALUES (USER(), 22), (USER(), 23); +--error ER_DUP_ENTRY +INSERT INTO nt_2 VALUES (USER(), 24), (USER(), 25); +INSERT INTO tt_2 VALUES ("new text 26", 26); +COMMIT; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B T INSERT M...SELECT* C" with an error in INSERT M...SELECT* generates +--echo *** in the binlog the following entries: "Nothing". +--echo *** There is a bug in that will be fixed after WL#2687. Please, check BUG#47175 for further details. +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +TRUNCATE TABLE nt_2; +TRUNCATE TABLE tt_2; +INSERT INTO tt_2 VALUES ("new text 7", 7); +BEGIN; +INSERT INTO tt_2 VALUES ("new text 27", 27); +--error ER_DUP_ENTRY +INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; +INSERT INTO tt_2 VALUES ("new text 28", 28); +ROLLBACK; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B INSERT M..SELECT* C" with an error in INSERT M...SELECT* generates +--echo *** in the binlog the following entries: "B INSERT M..SELECT* R". +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +TRUNCATE TABLE nt_2; +TRUNCATE TABLE tt_2; +INSERT INTO tt_2 VALUES ("new text 7", 7); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; +COMMIT; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B N N T C" generates in the binlog the "B N C B N C B T C" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +TRUNCATE TABLE nt_1; +TRUNCATE TABLE tt_2; +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 1); +INSERT INTO nt_1 VALUES (USER(), 2); +INSERT INTO tt_2 VALUES (USER(), 3); +COMMIT; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B N N T R" generates in the binlog the "B N C B N C B T R" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 4); +INSERT INTO nt_1 VALUES (USER(), 5); +INSERT INTO tt_2 VALUES (USER(), 6); +ROLLBACK; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B N* N* T C" with error in N* generates in the binlog the "B N R B N R B T C" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO nt_1 VALUES (USER(), 7), (USER(), 1); +--error ER_DUP_ENTRY +INSERT INTO nt_1 VALUES (USER(), 8), (USER(), 1); +INSERT INTO tt_2 VALUES (USER(), 9); +COMMIT; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B N* N* T R" with error in N* generates in the binlog the "B N R B N R B T R" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +BEGIN; +--error ER_DUP_ENTRY +INSERT INTO nt_1 VALUES (USER(), 10), (USER(), 1); +--error ER_DUP_ENTRY +INSERT INTO nt_1 VALUES (USER(), 11), (USER(), 1); +INSERT INTO tt_2 VALUES (USER(), 12); +ROLLBACK; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B N N T N T C" generates in the binlog the "B N C B N C B T N T C" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 13); +INSERT INTO nt_1 VALUES (USER(), 14); +INSERT INTO tt_2 VALUES (USER(), 15); +INSERT INTO nt_1 VALUES (USER(), 16); +INSERT INTO tt_2 VALUES (USER(), 17); +COMMIT; +--source include/show_binlog_events.inc + +--echo +--echo +--echo +--echo *** "B N N T N T R" generates in the binlog the "B N C B N C B T N T R" entries +--echo +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 18); +INSERT INTO nt_1 VALUES (USER(), 19); +INSERT INTO tt_2 VALUES (USER(), 20); +INSERT INTO nt_1 VALUES (USER(), 21); +INSERT INTO tt_2 VALUES (USER(), 22); +ROLLBACK; +--source include/show_binlog_events.inc + +--echo ################################################################################### +--echo # CLEAN +--echo ################################################################################### + +DROP TABLE tt_1; +DROP TABLE tt_2; +DROP TABLE nt_1; +DROP TABLE nt_2; diff --git a/mysql-test/extra/binlog_tests/drop_temp_table.test b/mysql-test/extra/binlog_tests/drop_temp_table.test index 7d37fca2bef..63833c10c14 100644 --- a/mysql-test/extra/binlog_tests/drop_temp_table.test +++ b/mysql-test/extra/binlog_tests/drop_temp_table.test @@ -1,27 +1,72 @@ --disable_warnings -drop database if exists `drop-temp+table-test`; +DROP DATABASE IF EXISTS `drop-temp+table-test`; --enable_warnings connect (con1,localhost,root,,); connect (con2,localhost,root,,); connection con1; -reset master; -create database `drop-temp+table-test`; -use `drop-temp+table-test`; -create temporary table shortn1 (a int); -create temporary table `table:name` (a int); -create temporary table shortn2 (a int); -select get_lock("a",10); +RESET MASTER; +CREATE DATABASE `drop-temp+table-test`; +USE `drop-temp+table-test`; +CREATE TEMPORARY TABLE shortn1 (a INT); +CREATE TEMPORARY TABLE `table:name` (a INT); +CREATE TEMPORARY TABLE shortn2 (a INT); + +############################################################################## +# BUG#46572 DROP TEMPORARY table IF EXISTS does not have a consistent behavior +# in ROW mode +# +# In RBR, 'DROP TEMPORARY TABLE ...' statement should never be binlogged no +# matter if the tables exist or not. In contrast, both in SBR and MBR, the +# statement should be always binlogged no matter if the tables exist or not. +############################################################################## +CREATE TEMPORARY TABLE tmp(c1 int); +CREATE TEMPORARY TABLE tmp1(c1 int); +CREATE TEMPORARY TABLE tmp2(c1 int); +CREATE TEMPORARY TABLE tmp3(c1 int); +CREATE TABLE t(c1 int); + +DROP TEMPORARY TABLE IF EXISTS tmp; + +--disable_warnings +# Before fixing BUG#46572, 'DROP TEMPORARY TABLE IF EXISTS...' statement was +# binlogged when the table did not exist in RBR. +DROP TEMPORARY TABLE IF EXISTS tmp; + +# In RBR, 'DROP TEMPORARY TABLE ...' statement is never binlogged no matter if +# the tables exist or not. +DROP TEMPORARY TABLE IF EXISTS tmp, tmp1; +DROP TEMPORARY TABLE tmp3; + +#In RBR, tmp2 will NOT be binlogged, because it is a temporary table. +DROP TABLE IF EXISTS tmp2, t; + +#In RBR, tmp2 will be binlogged, because it does not exist and master do not know +# whether it is a temporary table or not. +DROP TABLE IF EXISTS tmp2, t; +--enable_warnings + +SELECT GET_LOCK("a",10); + +# +# BUG48216 Replication fails on all slaves after upgrade to 5.0.86 on master +# +# When the session is closed, any temporary tables of the session are dropped +# and are binlogged. But it will be binlogged with a wrong database name when +# the length of the database name('drop-temp-table-test') is greater than the +# current database name('test'). +# +USE test; disconnect con1; connection con2; # We want to SHOW BINLOG EVENTS, to know what was logged. But there is no # guarantee that logging of the terminated con1 has been done yet. # To be sure that logging has been done, we use a user lock. -select get_lock("a",10); -let $VERSION=`select version()`; +SELECT GET_LOCK("a",10); +let $VERSION=`SELECT VERSION()`; source include/show_binlog_events.inc; -drop database `drop-temp+table-test`; +DROP DATABASE `drop-temp+table-test`; # End of 4.1 tests diff --git a/mysql-test/extra/rpl_tests/rpl_auto_increment.test b/mysql-test/extra/rpl_tests/rpl_auto_increment.test index 4bcb10c165e..86885a14f94 100644 --- a/mysql-test/extra/rpl_tests/rpl_auto_increment.test +++ b/mysql-test/extra/rpl_tests/rpl_auto_increment.test @@ -163,5 +163,81 @@ show create table t1; connection master; drop table t1; +# +# BUG#45999 Row based replication fails when auto_increment field = 0. +# Store engine of Slaves auto-generates new sequence numbers for +# auto_increment fields if the values of them are 0. There is an inconsistency +# between slave and master. When MODE_NO_AUTO_VALUE_ON_ZERO are masters treat +# +source include/master-slave-reset.inc; + +connection master; +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +--enable_warnings + +eval CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY) ENGINE=$engine_type; +eval CREATE TABLE t2 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY) ENGINE=$engine_type2; +SET SQL_MODE=''; +# Value of the id will be 1; +INSERT INTO t1 VALUES(NULL); +INSERT INTO t2 VALUES(NULL); +SELECT * FROM t1; +SELECT * FROM t2; +# Value of the id will be 2; +INSERT INTO t1 VALUES(); +INSERT INTO t2 VALUES(); +SELECT * FROM t1; +SELECT * FROM t2; +# Value of the id will be 3. The master treats 0 as NULL or empty because +# NO_AUTO_VALUE_ON_ZERO is not assign to SQL_MODE. +INSERT INTO t1 VALUES(0); +INSERT INTO t2 VALUES(0); +SELECT * FROM t1; +SELECT * FROM t2; + +SET SQL_MODE=NO_AUTO_VALUE_ON_ZERO; +# Value of the id will be 0. The master does not treat 0 as NULL or empty +# because NO_AUTO_VALUE_ON_ZERO has assigned to SQL_MODE. +INSERT INTO t1 VALUES(0); +INSERT INTO t2 VALUES(0); +SELECT * FROM t1; +SELECT * FROM t2; + +INSERT INTO t1 VALUES(4); +INSERT INTO t2 VALUES(4); +FLUSH LOGS; +sync_slave_with_master; + +let $diff_table_1= master:test.t1; +let $diff_table_2= slave:test.t1; +source include/diff_tables.inc; + +let $diff_table_1= master:test.t2; +let $diff_table_2= slave:test.t2; +source include/diff_tables.inc; + +connection master; +DROP TABLE t1; +DROP TABLE t2; +sync_slave_with_master; + +connection master; +let $MYSQLD_DATADIR= `SELECT @@DATADIR`; +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 | $MYSQL test +sync_slave_with_master; + +let $diff_table_1= master:test.t1; +let $diff_table_2= slave:test.t1; +source include/diff_tables.inc; + +let $diff_table_1= master:test.t2; +let $diff_table_2= slave:test.t2; +source include/diff_tables.inc; + # End cleanup +DROP TABLE t1; +DROP TABLE t2; +SET SQL_MODE=''; sync_slave_with_master; diff --git a/mysql-test/extra/rpl_tests/rpl_auto_increment_insert_view.test b/mysql-test/extra/rpl_tests/rpl_auto_increment_insert_view.test new file mode 100644 index 00000000000..0bfa46de113 --- /dev/null +++ b/mysql-test/extra/rpl_tests/rpl_auto_increment_insert_view.test @@ -0,0 +1,44 @@ +# +# This test verifies if inserting data into view that invokes a +# trigger will make the autoinc values become inconsistent on +# master and slave. +# +connection master; +CREATE TABLE t1(i1 int not null auto_increment, c1 INT, primary key(i1)) engine=innodb; +CREATE TABLE t2(i1 int not null auto_increment, c2 INT, primary key(i1)) engine=innodb; +CREATE TABLE t3(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +eval create trigger tr16 $insert_action on t1 for each row insert into t3(a) values(new.c1); +eval create trigger tr17 $insert_action on t2 for each row insert into t3(a) values(new.c2); +begin; +INSERT INTO t1(c1) VALUES (11), (12); +INSERT INTO t2(c2) VALUES (13), (14); + +CREATE VIEW v16 AS SELECT c1, c2 FROM t1, t2; + +INSERT INTO v16(c1) VALUES (15),(16); +INSERT INTO v16(c2) VALUES (17),(18); + +connection master1; +INSERT INTO v16(c1) VALUES (19),(20); +INSERT INTO v16(c2) VALUES (21),(22); + +connection master; +INSERT INTO v16(c1) VALUES (23), (24); +INSERT INTO v16(c1) VALUES (25), (26); +commit; +sync_slave_with_master; +--echo #Test if the results are consistent on master and slave +--echo #for 'INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS' +let $diff_table_1=master:test.t3; +let $diff_table_2=slave:test.t3; +source include/diff_tables.inc; + +connection master; +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP VIEW v16; +sync_slave_with_master; + + + diff --git a/mysql-test/extra/rpl_tests/rpl_auto_increment_invoke_trigger.test b/mysql-test/extra/rpl_tests/rpl_auto_increment_invoke_trigger.test new file mode 100644 index 00000000000..614d79d9c2d --- /dev/null +++ b/mysql-test/extra/rpl_tests/rpl_auto_increment_invoke_trigger.test @@ -0,0 +1,82 @@ +# +# This test verifies if concurrent transactions that invoke a +# trigger that inserts more than one values into one or more +# tables with an auto_increment column will make the autoinc +# values become inconsistent on master and slave. +# + +connection master; +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +eval create trigger tr1 $trigger_action on t1 for each row insert into t2(a) values(6); + +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +delimiter |; +eval create trigger tr2 $trigger_action on t3 for each row begin + insert into t4(a) values(f1_insert_triggered()); + insert into t4(a) values(f1_insert_triggered()); + insert into t5(a) values(8); +end | +delimiter ;| + +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +delimiter //; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN + INSERT INTO t6(a) values(2),(3); + RETURN 1; +END// +delimiter ;// + +begin; +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; + +connection master1; +#The default autocommit is set to 1, so the statement is auto committed +insert into t2(a) values(3); +insert into t4(a) values(3); + +connection master; +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +--echo # To verify if insert/update in an autoinc column causes statement to be logged in row format +source include/show_binlog_events.inc; +commit; + +connection master; +sync_slave_with_master; +--echo #Test if the results are consistent on master and slave +--echo #for 'INVOKES A TRIGGER with $trigger_action action' +let $diff_table_1=master:test.t2; +let $diff_table_2=slave:test.t2; +source include/diff_tables.inc; +let $diff_table_1=master:test.t4; +let $diff_table_2=slave:test.t4; +source include/diff_tables.inc; +let $diff_table_1=master:test.t6; +let $diff_table_2=slave:test.t6; +source include/diff_tables.inc; + +connection master; +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +sync_slave_with_master; + diff --git a/mysql-test/extra/rpl_tests/rpl_autoinc_func_invokes_trigger.test b/mysql-test/extra/rpl_tests/rpl_autoinc_func_invokes_trigger.test new file mode 100644 index 00000000000..fece19b397d --- /dev/null +++ b/mysql-test/extra/rpl_tests/rpl_autoinc_func_invokes_trigger.test @@ -0,0 +1,57 @@ +# +# This test verifies if concurrent transactions that call a +# function which invokes a 'after/before insert action' trigger +# that inserts more than one values into a table with autoinc +# column will make the autoinc values become inconsistent on +# master and slave. +# + +connection master; +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t3(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +delimiter |; +CREATE FUNCTION f1_two_inserts_trigger() RETURNS INTEGER +BEGIN + INSERT INTO t2(a) values(2),(3); + INSERT INTO t2(a) values(2),(3); + RETURN 1; +END | +eval create trigger tr11 $insert_action on t2 for each row begin + insert into t3(a) values(new.a); + insert into t3(a) values(new.a); +end | +delimiter ;| +begin; +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +insert into t1(a) values(f1_two_inserts_trigger()); + +connection master1; +#The default autocommit is set to 1, so the statement is auto committed +insert into t2(a) values(4),(5); + +connection master; +commit; +insert into t1(a) values(f1_two_inserts_trigger()); +--echo # To verify if insert/update in an autoinc column causes statement to be logged in row format +source include/show_binlog_events.inc; +commit; + +connection master; +sync_slave_with_master; +--echo #Test if the results are consistent on master and slave +--echo #for 'CALLS A FUNCTION which INVOKES A TRIGGER with $insert_action action' +let $diff_table_1=master:test.t2; +let $diff_table_2=slave:test.t2; +source include/diff_tables.inc; +let $diff_table_1=master:test.t3; +let $diff_table_2=slave:test.t3; +source include/diff_tables.inc; + +connection master; +drop table t1; +drop table t2; +drop table t3; +drop function f1_two_inserts_trigger; +sync_slave_with_master; + diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test index 6890913b7d1..a7b02065144 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test @@ -22,6 +22,8 @@ DROP TABLE IF EXISTS t1, t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t14a,t15,t1 # should stop the slave. # ################################################# +call mtr.add_suppression("Slave: Unknown table 't6' Error_code: 1051"); + --echo **** Diff Table Def Start **** ############################################## diff --git a/mysql-test/extra/rpl_tests/rpl_failed_optimize.test b/mysql-test/extra/rpl_tests/rpl_failed_optimize.test index 0c537ee188d..cd81f2497b8 100644 --- a/mysql-test/extra/rpl_tests/rpl_failed_optimize.test +++ b/mysql-test/extra/rpl_tests/rpl_failed_optimize.test @@ -22,3 +22,4 @@ connection master; select * from t1; commit; drop table t1; +-- sync_slave_with_master diff --git a/mysql-test/extra/rpl_tests/rpl_loaddata.test b/mysql-test/extra/rpl_tests/rpl_loaddata.test index 26916642cae..7db12600456 100644 --- a/mysql-test/extra/rpl_tests/rpl_loaddata.test +++ b/mysql-test/extra/rpl_tests/rpl_loaddata.test @@ -158,4 +158,65 @@ LOAD DATA INFILE "../../std_data/words.dat" INTO TABLE t1; DROP TABLE IF EXISTS t1; +# BUG#48297: Schema name is ignored when LOAD DATA is written into binlog, +# replication aborts +-- source include/master-slave-reset.inc + +-- let $db1= b48297_db1 +-- let $db2= b42897_db2 + +-- connection master + +-- disable_warnings +-- eval drop database if exists $db1 +-- eval drop database if exists $db2 +-- enable_warnings + +-- eval create database $db1 +-- eval create database $db2 + +-- eval use $db1 +-- eval CREATE TABLE t1 (c1 VARCHAR(256)) engine=$engine_type; + +-- eval use $db2 + +-- echo ### assertion: works with cross-referenced database +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1 + +-- eval use $db1 +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- echo ### assertion: works with fully qualified name on current database +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1 + +-- echo ### assertion: works without fully qualified name on current database +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE t1 + +-- echo ### create connection without default database +-- echo ### connect (conn2,localhost,root,,*NO-ONE*); +connect (conn2,localhost,root,,*NO-ONE*); +-- connection conn2 +-- echo ### assertion: works without stating the default database +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval LOAD DATA LOCAL INFILE '$MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE $db1.t1 +-- echo ### disconnect and switch back to master connection +-- disconnect conn2 +-- connection master + +-- sync_slave_with_master +-- eval use $db1 + +let $diff_table_1=master:$db1.t1; +let $diff_table_2=slave:$db1.t1; +source include/diff_tables.inc; + +-- connection master + +-- eval DROP DATABASE $db1 +-- eval DROP DATABASE $db2 + +-- sync_slave_with_master + # End of 4.1 tests diff --git a/mysql-test/extra/rpl_tests/rpl_row_sp006.test b/mysql-test/extra/rpl_tests/rpl_row_sp006.test index 897d7e492bf..16a8374ae7f 100644 --- a/mysql-test/extra/rpl_tests/rpl_row_sp006.test +++ b/mysql-test/extra/rpl_tests/rpl_row_sp006.test @@ -9,29 +9,27 @@ ############################################################################# # Begin clean up test section -connection master; --disable_warnings -create database if not exists mysqltest1; -DROP PROCEDURE IF EXISTS mysqltest1.p1; -DROP PROCEDURE IF EXISTS mysqltest1.p2; -DROP TABLE IF EXISTS mysqltest1.t2; -DROP TABLE IF EXISTS mysqltest1.t1; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; --enable_warnings # End of cleanup # Begin test section 1 -eval CREATE TABLE IF NOT EXISTS mysqltest1.t1(name CHAR(16), birth DATE,PRIMARY KEY(name))ENGINE=$engine_type; -eval CREATE TABLE IF NOT EXISTS mysqltest1.t2(name CHAR(16), age INT ,PRIMARY KEY(name))ENGINE=$engine_type; +eval CREATE TABLE IF NOT EXISTS t1(name CHAR(16), birth DATE,PRIMARY KEY(name))ENGINE=$engine_type; +eval CREATE TABLE IF NOT EXISTS t2(name CHAR(16), age INT ,PRIMARY KEY(name))ENGINE=$engine_type; delimiter |; -CREATE PROCEDURE mysqltest1.p1() +CREATE PROCEDURE p1() BEGIN DECLARE done INT DEFAULT 0; DECLARE spa CHAR(16); DECLARE spb INT; DECLARE cur1 CURSOR FOR SELECT name, (YEAR(CURDATE())-YEAR(birth))-(RIGHT(CURDATE(),5)<RIGHT(birth,5)) - FROM mysqltest1.t1; + FROM t1; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; OPEN cur1; @@ -41,7 +39,7 @@ BEGIN FETCH cur1 INTO spa, spb; IF NOT done THEN START TRANSACTION; - INSERT INTO mysqltest1.t2 VALUES (spa,spb); + INSERT INTO t2 VALUES (spa,spb); COMMIT; END IF; UNTIL done END REPEAT; @@ -49,30 +47,29 @@ BEGIN SET AUTOCOMMIT=1; CLOSE cur1; END| -CREATE PROCEDURE mysqltest1.p2() +CREATE PROCEDURE p2() BEGIN - INSERT INTO mysqltest1.t1 VALUES ('MySQL','1993-02-04'),('ROCKS', '1990-08-27'),('Texas', '1999-03-30'),('kyle','2005-1-1'); + INSERT INTO t1 VALUES ('MySQL','1993-02-04'),('ROCKS', '1990-08-27'),('Texas', '1999-03-30'),('kyle','2005-1-1'); END| delimiter ;| -CALL mysqltest1.p2(); +CALL p2(); sync_slave_with_master; connection master; -CALL mysqltest1.p1(); +CALL p1(); sync_slave_with_master; connection master; ---exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/sp006_master.sql ---exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/sp006_slave.sql +--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/sp006_master.sql +--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/sp006_slave.sql -DROP PROCEDURE IF EXISTS mysqltest1.p1; -DROP PROCEDURE IF EXISTS mysqltest1.p2; -DROP TABLE IF EXISTS mysqltest1.t1; -DROP TABLE IF EXISTS mysqltest1.t2; -DROP DATABASE mysqltest1; +DROP TABLE t1; +DROP TABLE t2; +DROP PROCEDURE p1; +DROP PROCEDURE p2; # Lets compare. Note: If they match test will pass, if they do not match # the test will show that the diff statement failed and not reject file diff --git a/mysql-test/extra/rpl_tests/rpl_stm_000001.test b/mysql-test/extra/rpl_tests/rpl_stm_000001.test index 1f5eb5786dd..869a9e3b07c 100644 --- a/mysql-test/extra/rpl_tests/rpl_stm_000001.test +++ b/mysql-test/extra/rpl_tests/rpl_stm_000001.test @@ -93,7 +93,7 @@ kill @id; # We don't drop t3 as this is a temporary table drop table t2; connection master; ---error 1053,2013 +--error 1317,2013 reap; connection slave; # The SQL slave thread should now have stopped because the query was killed on diff --git a/mysql-test/include/check-warnings.test b/mysql-test/include/check-warnings.test index 8267ccdd102..fab7fb2cff6 100644 --- a/mysql-test/include/check-warnings.test +++ b/mysql-test/include/check-warnings.test @@ -58,5 +58,5 @@ if (`select @result = 0`){ skip OK; } --enable_query_log -echo ^ Found warnings!!; +echo ^ Found warnings in $log_error; exit; diff --git a/mysql-test/include/concurrent.inc b/mysql-test/include/concurrent.inc index 66f8a65a102..0b7299a3c34 100644 --- a/mysql-test/include/concurrent.inc +++ b/mysql-test/include/concurrent.inc @@ -25,8 +25,6 @@ # new wrapper t/concurrent_innodb_safelog.test # ---source include/not_embedded.inc - connection default; # # Show prerequisites for this test. diff --git a/mysql-test/include/have_case_insensitive_fs.inc b/mysql-test/include/have_case_insensitive_fs.inc new file mode 100644 index 00000000000..de4ad73d780 --- /dev/null +++ b/mysql-test/include/have_case_insensitive_fs.inc @@ -0,0 +1,4 @@ +--require r/case_insensitive_fs.require +--disable_query_log +show variables like 'lower_case_file_system'; +--enable_query_log diff --git a/mysql-test/include/have_debug_sync.inc b/mysql-test/include/have_debug_sync.inc new file mode 100644 index 00000000000..7aa5baf3342 --- /dev/null +++ b/mysql-test/include/have_debug_sync.inc @@ -0,0 +1,5 @@ +--require r/have_debug_sync.require +disable_query_log; +let $value= query_get_value(SHOW VARIABLES LIKE 'debug_sync', Value, 1); +eval SELECT ('$value' LIKE 'ON %') AS debug_sync; +enable_query_log; diff --git a/mysql-test/include/have_dynamic_loading.inc b/mysql-test/include/have_dynamic_loading.inc index ddd7c61a730..1b2c85b3904 100644 --- a/mysql-test/include/have_dynamic_loading.inc +++ b/mysql-test/include/have_dynamic_loading.inc @@ -1,4 +1,7 @@ --- require r/have_dynamic_loading.require +# +# Whether server supports dynamic loading. +# +--require r/have_dynamic_loading.require disable_query_log; show variables like 'have_dynamic_loading'; enable_query_log; diff --git a/mysql-test/include/have_example_plugin.inc b/mysql-test/include/have_example_plugin.inc index 8e57c725eb5..a2fffc17b97 100644 --- a/mysql-test/include/have_example_plugin.inc +++ b/mysql-test/include/have_example_plugin.inc @@ -2,10 +2,7 @@ # Check if server has support for loading udf's # i.e it will support dlopen # ---require r/have_dynamic_loading.require -disable_query_log; -show variables like 'have_dynamic_loading'; -enable_query_log; +--source include/have_dynamic_loading.inc # # Check if the variable EXAMPLE_PLUGIN is set diff --git a/mysql-test/include/have_mysql_upgrade.inc b/mysql-test/include/have_mysql_upgrade.inc new file mode 100644 index 00000000000..8f486176018 --- /dev/null +++ b/mysql-test/include/have_mysql_upgrade.inc @@ -0,0 +1,4 @@ +--require r/have_mysql_upgrade.result +--disable_query_log +select LENGTH("$MYSQL_UPGRADE")>0 as have_mysql_upgrade; +--enable_query_log diff --git a/mysql-test/include/have_not_innodb_plugin.inc b/mysql-test/include/have_not_innodb_plugin.inc new file mode 100644 index 00000000000..aaefbaf661c --- /dev/null +++ b/mysql-test/include/have_not_innodb_plugin.inc @@ -0,0 +1,4 @@ +disable_query_log; +--require r/not_true.require +select (PLUGIN_LIBRARY LIKE 'ha_innodb_plugin%') as `TRUE` from information_schema.plugins where PLUGIN_NAME='InnoDB'; +enable_query_log; diff --git a/mysql-test/include/have_simple_parser.inc b/mysql-test/include/have_simple_parser.inc index c85786bd524..5a4dc93ec81 100644 --- a/mysql-test/include/have_simple_parser.inc +++ b/mysql-test/include/have_simple_parser.inc @@ -2,10 +2,7 @@ # Check if server has support for loading udf's # i.e it will support dlopen # ---require r/have_dynamic_loading.require -disable_query_log; -show variables like 'have_dynamic_loading'; -enable_query_log; +--source include/have_dynamic_loading.inc # # Check if the variable SIMPLE_PARSER is set diff --git a/mysql-test/include/have_udf.inc b/mysql-test/include/have_udf.inc index 3f7e260c5ba..7be57bbb7a9 100644 --- a/mysql-test/include/have_udf.inc +++ b/mysql-test/include/have_udf.inc @@ -2,10 +2,7 @@ # Check if server has support for loading udf's # i.e it will support dlopen # ---require r/have_dynamic_loading.require -disable_query_log; -show variables like 'have_dynamic_loading'; -enable_query_log; +--source include/have_dynamic_loading.inc # # Check if the variable UDF_EXAMPLE_LIB is set diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index 6dabe4864a9..194d9e41108 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -442,6 +442,8 @@ INSERT INTO t1(id, dept, age, name) VALUES EXPLAIN SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; DELETE FROM t1; +--echo # Masking (#) number in "rows" column of the following EXPLAIN output, as it may vary (bug#47746). +--replace_column 9 # EXPLAIN SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql index af491d4fe8a..c1c9785fda2 100644 --- a/mysql-test/include/mtr_warnings.sql +++ b/mysql-test/include/mtr_warnings.sql @@ -132,7 +132,7 @@ INSERT INTO global_suppressions VALUES ("Error in Log_event::read_log_event\\\(\\\): 'Sanity check failed', data_len: 258, event_type: 49"), - ("Statement is not safe to log in statement format"), + ("Statement may not be safe to log in statement format"), /* test case for Bug#bug29807 copies a stray frm into database */ ("InnoDB: Error: table `test`.`bug29807` does not exist in the InnoDB internal"), @@ -162,6 +162,8 @@ INSERT INTO global_suppressions VALUES ("Slave: Unknown column 'c7' in 't15' Error_code: 1054"), ("Slave: Can't DROP 'c7'.* 1091"), ("Slave: Key column 'c6'.* 1072"), + ("The slave I.O thread stops because a fatal error is encountered when it try to get the value of SERVER_ID variable from master."), + (".SELECT UNIX_TIMESTAMP... failed on master, do not trust column Seconds_Behind_Master of SHOW SLAVE STATUS"), /* Test case for Bug#31590 in order_by.test produces the following error */ ("Out of sort memory; increase server sort buffer size"), @@ -171,6 +173,7 @@ INSERT INTO global_suppressions VALUES this error message. */ ("Can't find file: '.\\\\test\\\\\\?{8}.frm'"), + ("Slave: Unknown table 't1' Error_code: 1051"), /* maria-recovery.test has warning about missing log file */ ("File '.*maria_log.000.*' not found \\(Errcode: 2\\)"), @@ -217,7 +220,7 @@ BEGIN WHERE suspicious=1; IF @num_warnings > 0 THEN - SELECT file_name, line + SELECT line FROM error_log WHERE suspicious=1; --SELECT * FROM test_suppressions; -- Return 2 -> check failed diff --git a/mysql-test/include/not_windows_embedded.inc b/mysql-test/include/not_windows_embedded.inc new file mode 100644 index 00000000000..46f5e0ccfce --- /dev/null +++ b/mysql-test/include/not_windows_embedded.inc @@ -0,0 +1,11 @@ +let $is_win = `select convert(@@version_compile_os using latin1) IN ("Win32","Win64","Windows")`; +let $is_embedded = `select version() like '%embedded%'`; +#echo is_win: $is_win; +#echo is_embedded: $is_embedded; +if ($is_win) +{ + if ($is_embedded) + { + skip Not supported with embedded on windows; + } +} diff --git a/mysql-test/lib/My/ConfigFactory.pm b/mysql-test/lib/My/ConfigFactory.pm index 855918a1284..349cf3c4c05 100644 --- a/mysql-test/lib/My/ConfigFactory.pm +++ b/mysql-test/lib/My/ConfigFactory.pm @@ -7,6 +7,7 @@ use Carp; use My::Config; use My::Find; +use My::Platform; use File::Basename; @@ -207,8 +208,8 @@ my @mysqld_rules= { '#log-error' => \&fix_log_error }, { 'general-log' => sub { return 1; } }, { 'general-log-file' => \&fix_log }, - { 'slow-query-log-file' => \&fix_log_slow_queries }, { 'slow-query-log' => sub { return 1; } }, + { 'slow-query-log-file' => \&fix_log_slow_queries }, { '#user' => sub { return shift->{ARGS}->{user} || ""; } }, { '#password' => sub { return shift->{ARGS}->{password} || ""; } }, { 'server-id' => \&fix_server_id, }, @@ -219,7 +220,13 @@ my @mysqld_rules= { 'ssl-key' => \&fix_ssl_server_key }, ); - +if (IS_WINDOWS) +{ + # For simplicity, we use the same names for shared memory and + # named pipes. + push(@mysqld_rules, {'shared-memory-base-name' => \&fix_socket}); +} + sub fix_ndb_mgmd_port { my ($self, $config, $group_name, $group)= @_; my $hostname= $group->value('HostName'); @@ -348,6 +355,16 @@ sub post_check_client_group { } $config->insert($client_group_name, $name_to, $option->value()) } + + if (IS_WINDOWS) + { + # Shared memory base may or may not be defined (e.g not defined in embedded) + my $shm = $group_to_copy_from->option("shared-memory-base-name"); + if (defined $shm) + { + $config->insert($client_group_name,"shared-memory-base-name", $shm->value()); + } + } } @@ -394,6 +411,7 @@ sub post_check_embedded_group { ( '#log-error', # Embedded server writes stderr to mysqltest's log file 'slave-net-timeout', # Embedded server are not build with replication + 'shared-memory-base-name', # No shared memory for embedded ); foreach my $option ( $mysqld->options(), $first_mysqld->options() ) { diff --git a/mysql-test/lib/My/Platform.pm b/mysql-test/lib/My/Platform.pm index 69ffdfbb4ce..371120ab644 100644 --- a/mysql-test/lib/My/Platform.pm +++ b/mysql-test/lib/My/Platform.pm @@ -106,10 +106,13 @@ sub check_socket_path_length { my ($path)= @_; return 0 if IS_WINDOWS; + # This may not be true, but we can't test for it on AIX due to Perl bug + # See Bug #45771 + return 0 if ($^O eq 'aix'); require IO::Socket::UNIX; - my $truncated= 1; # Be negative + my $truncated= undef; # Create a tempfile name with same length as "path" my $tmpdir = tempdir( CLEANUP => 0); @@ -122,6 +125,7 @@ sub check_socket_path_length { Local => $testfile, Listen => 1, ); + $truncated= 1; # Be negatvie die "Could not create UNIX domain socket: $!" unless defined $sock; @@ -133,6 +137,9 @@ sub check_socket_path_length { }; + die "Unexpected failure when checking socket path length: $@" + if $@ and not defined $truncated; + $sock= undef; # Close socket rmtree($tmpdir); # Remove the tempdir and any socket file created return $truncated; diff --git a/mysql-test/lib/My/SafeProcess/safe_kill_win.cc b/mysql-test/lib/My/SafeProcess/safe_kill_win.cc index c6256fd92e1..963a02c8099 100755 --- a/mysql-test/lib/My/SafeProcess/safe_kill_win.cc +++ b/mysql-test/lib/My/SafeProcess/safe_kill_win.cc @@ -30,7 +30,7 @@ int main(int argc, const char** argv ) DWORD pid= -1; HANDLE shutdown_event; char safe_process_name[32]= {0}; - int retry_open_event= 100; + int retry_open_event= 2; /* Ignore any signals */ signal(SIGINT, SIG_IGN); signal(SIGBREAK, SIG_IGN); @@ -51,15 +51,31 @@ int main(int argc, const char** argv ) { /* Check if the process is alive, otherwise there is really - no idea to retry the open of the event + no sense to retry the open of the event */ HANDLE process; - if ((process= OpenProcess(SYNCHRONIZE, FALSE, pid)) == NULL) + DWORD exit_code; + process= OpenProcess(SYNCHRONIZE| PROCESS_QUERY_INFORMATION, FALSE, pid); + if (!process) { - fprintf(stderr, "Could not open event or process %d, error: %d\n", - pid, GetLastError()); - exit(3); + /* Already died */ + exit(1); + } + + if (!GetExitCodeProcess(process,&exit_code)) + { + fprintf(stderr, "GetExitCodeProcess failed, pid= %d, err= %d\n", + pid, GetLastError()); + exit(1); } + + if (exit_code != STILL_ACTIVE) + { + /* Already died */ + CloseHandle(process); + exit(2); + } + CloseHandle(process); if (retry_open_event--) diff --git a/mysql-test/lib/My/SafeProcess/safe_process_win.cc b/mysql-test/lib/My/SafeProcess/safe_process_win.cc index 213989720bf..aa9093fb2b4 100755 --- a/mysql-test/lib/My/SafeProcess/safe_process_win.cc +++ b/mysql-test/lib/My/SafeProcess/safe_process_win.cc @@ -50,9 +50,6 @@ is killed. */ -/* Requires Windows 2000 or higher */ -#define _WIN32_WINNT 0x0500 - #include <windows.h> #include <stdio.h> #include <tlhelp32.h> @@ -189,7 +186,14 @@ int main(int argc, const char** argv ) die("No real args -> nothing to do"); /* Copy the remaining args to child_arg */ for (int j= i+1; j < argc; j++) { - to+= _snprintf(to, child_args + sizeof(child_args) - to, "%s ", argv[j]); + if (strchr (argv[j], ' ')) { + /* Protect with "" if this arg contains a space */ + to+= _snprintf(to, child_args + sizeof(child_args) - to, + "\"%s\" ", argv[j]); + } else { + to+= _snprintf(to, child_args + sizeof(child_args) - to, + "%s ", argv[j]); + } } break; } else { diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 76575b2f498..28b79484aa8 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -41,6 +41,7 @@ our $opt_with_ndbcluster_only; our $defaults_file; our $defaults_extra_file; our $reorder= 1; +our $quick_collect; sub collect_option { my ($opt, $value)= @_; @@ -68,6 +69,13 @@ require "mtr_misc.pl"; my $do_test_reg; my $skip_test_reg; +# Related to adding InnoDB plugin combinations +my $lib_innodb_plugin; +my $do_innodb_plugin; + +# If "Quick collect", set to 1 once a test to run has been found. +my $some_test_found; + sub init_pattern { my ($from, $what)= @_; return undef unless defined $from; @@ -100,10 +108,23 @@ sub collect_test_cases ($$) { $do_test_reg= init_pattern($do_test, "--do-test"); $skip_test_reg= init_pattern($skip_test, "--skip-test"); + $lib_innodb_plugin= + my_find_file($::basedir, + ["storage/innodb_plugin", "storage/innodb_plugin/.libs", + "lib/mysql/plugin", "lib/mariadb/plugin", "lib/plugin"], + ["ha_innodb_plugin.dll", "ha_innodb_plugin.so", + "ha_innodb_plugin.sl"], + NOT_REQUIRED); + + $do_innodb_plugin= ($::mysql_version_id >= 50100 && + !(IS_WINDOWS && $::opt_embedded_server) && + $lib_innodb_plugin); + foreach my $suite (split(",", $suites)) { push(@$cases, collect_one_suite($suite, $opt_cases)); $found_suites{$suite}= 1; + last if $some_test_found; } if ( @$opt_cases ) @@ -147,7 +168,7 @@ sub collect_test_cases ($$) { } } - if ( $reorder ) + if ( $reorder && !$quick_collect) { # Reorder the test cases in an order that will make them faster to run my %sort_criteria; @@ -398,7 +419,7 @@ sub collect_one_suite($) # Read combinations for this suite and build testcases x combinations # if any combinations exists # ---------------------------------------------------------------------- - if ( ! $skip_combinations ) + if ( ! $skip_combinations && ! $quick_collect ) { my @combinations; my $combination_file= "$suitedir/combinations"; @@ -491,21 +512,16 @@ sub collect_one_suite($) # ---------------------------------------------------------------------- # Testing InnoDB plugin. # ---------------------------------------------------------------------- - my $lib_innodb_plugin= - mtr_file_exists(::vs_config_dirs('storage/innodb_plugin', 'ha_innodb_plugin.dll'), - "$::basedir/storage/innodb_plugin/.libs/ha_innodb_plugin.so", - "$::basedir/lib/mariadb/plugin/ha_innodb_plugin.so", - "$::basedir/lib/mariadb/plugin/ha_innodb_plugin.dll", - "$::basedir/lib/mysql/plugin/ha_innodb_plugin.so", - "$::basedir/lib/mysql/plugin/ha_innodb_plugin.dll"); - if ($::mysql_version_id >= 50100 && !(IS_WINDOWS && $::opt_embedded_server) && - $lib_innodb_plugin) + if ($do_innodb_plugin) { my @new_cases; + my $sep= (IS_WINDOWS) ? ';' : ':'; foreach my $test (@cases) { - next if ($test->{'skip'} || !$test->{'innodb_test'}); + next if (!$test->{'innodb_test'}); + # If skipped due to no builtin innodb, we can still run it with plugin + next if ($test->{'skip'} && $test->{comment} ne "No innodb support"); # Exceptions next if ($test->{'name'} eq 'main.innodb'); # Failed with wrong errno (fk) next if ($test->{'name'} eq 'main.index_merge_innodb'); # Explain diff @@ -515,6 +531,8 @@ sub collect_one_suite($) next if ($test->{'name'} eq 'sys_vars.innodb_lock_wait_timeout_basic'); # Diff around innodb_thread_concurrency variable next if ($test->{'name'} eq 'sys_vars.innodb_thread_concurrency_basic'); + # Can't work with InnoPlug. Test framework needs to be re-designed. + next if ($test->{'name'} eq 'main.innodb_bug46000'); # Copy test options my $new_test= My::Test->new(); while (my ($key, $value) = each(%$test)) @@ -525,23 +543,24 @@ sub collect_one_suite($) } else { - $new_test->{$key}= $value; + $new_test->{$key}= $value unless ($key eq 'skip'); } } my $plugin_filename= basename($lib_innodb_plugin); + my $plugin_list= "innodb=$plugin_filename" . $sep . "innodb_locks=$plugin_filename"; push(@{$new_test->{master_opt}}, '--ignore-builtin-innodb'); push(@{$new_test->{master_opt}}, '--plugin-dir=' . dirname($lib_innodb_plugin)); - push(@{$new_test->{master_opt}}, "--plugin_load=innodb=$plugin_filename;innodb_locks=$plugin_filename"); + push(@{$new_test->{master_opt}}, "--plugin_load=$plugin_list"); push(@{$new_test->{slave_opt}}, '--ignore-builtin-innodb'); push(@{$new_test->{slave_opt}}, '--plugin-dir=' . dirname($lib_innodb_plugin)); - push(@{$new_test->{slave_opt}}, "--plugin_load=innodb=$plugin_filename;innodb_locks=$plugin_filename"); + push(@{$new_test->{slave_opt}}, "--plugin_load=$plugin_list"); if ($new_test->{combination}) { - $new_test->{combination}.= ' + InnoDB plugin'; + $new_test->{combination}.= '+innodb_plugin'; } else { - $new_test->{combination}= 'InnoDB plugin'; + $new_test->{combination}= 'innodb_plugin'; } push(@new_cases, $new_test); } @@ -670,34 +689,10 @@ sub optimize_cases { } } - # ======================================================= - # Check that engine selected by - # --default-storage-engine=<engine> is supported - # ======================================================= - my %builtin_engines = ('myisam' => 1, 'memory' => 1); - - foreach my $opt ( @{$tinfo->{master_opt}} ) { - my $default_engine= - mtr_match_prefix($opt, "--default-storage-engine="); - - if (defined $default_engine){ - - - my $engine_value= $::mysqld_variables{$default_engine}; - - if ( ! exists $::mysqld_variables{$default_engine} and - ! exists $builtin_engines{$default_engine} ) - { - $tinfo->{'skip'}= 1; - $tinfo->{'comment'}= - "'$default_engine' not supported"; - } - - $tinfo->{'ndb_test'}= 1 - if ( $default_engine =~ /^ndb/i ); - $tinfo->{'innodb_test'}= 1 - if ( $default_engine =~ /^innodb/i ); - } + if ($quick_collect && ! $tinfo->{'skip'}) + { + $some_test_found= 1; + return; } } @$cases= @new_cases; @@ -1001,21 +996,24 @@ sub collect_one_test_case { if ($tinfo->{'federated_test'}) { - # This is a test that need federated, enable it + # This is a test that needs federated, enable it push(@{$tinfo->{'master_opt'}}, "--loose-federated"); push(@{$tinfo->{'slave_opt'}}, "--loose-federated"); } if ( $tinfo->{'innodb_test'} ) { - # This is a test that need innodb + # This is a test that needs innodb if ( $::mysqld_variables{'innodb'} eq "OFF" || ! exists $::mysqld_variables{'innodb'} ) { # innodb is not supported, skip it $tinfo->{'skip'}= 1; + # This comment is checked for running with innodb plugin (see above), + # please keep that in mind if changing the text. $tinfo->{'comment'}= "No innodb support"; - return $tinfo; + # But continue processing if we may run it with innodb plugin + return $tinfo unless $do_innodb_plugin; } } else @@ -1071,6 +1069,17 @@ sub collect_one_test_case { } } + if ( $tinfo->{'need_ssl'} ) + { + # This is a test that needs ssl + if ( ! $::opt_ssl_supported ) { + # SSL is not supported, skip it + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No SSL support"; + return $tinfo; + } + } + # ---------------------------------------------------------------------- # Find config file to use if not already selected in <testname>.opt file # ---------------------------------------------------------------------- @@ -1163,7 +1172,8 @@ my @tags= ["federated.inc", "federated_test", 1], ["include/not_embedded.inc", "not_embedded", 1], ["include/not_valgrind.inc", "not_valgrind", 1], - ["include/have_example_plugin.inc", "example_plugin_test", 1] + ["include/have_example_plugin.inc", "example_plugin_test", 1], + ["include/have_ssl.inc", "need_ssl", 1], ); diff --git a/mysql-test/lib/mtr_report.pm b/mysql-test/lib/mtr_report.pm index bc27029351d..e0c5b004541 100644 --- a/mysql-test/lib/mtr_report.pm +++ b/mysql-test/lib/mtr_report.pm @@ -134,8 +134,8 @@ sub mtr_report_test ($) { # an asterisk at the end, determine if the characters up to # but excluding the asterisk are the same if ( $exp ne "" && substr($exp, -1, 1) eq "*" ) { - $exp = substr($exp, 0, length($exp) - 1); - if ( substr($test_name, 0, length($exp)) ne $exp ) { + my $nexp = substr($exp, 0, length($exp) - 1); + if ( substr($test_name, 0, length($nexp)) ne $nexp ) { # no match, try next entry next; } @@ -146,6 +146,7 @@ sub mtr_report_test ($) { } } $fail = "exp-fail"; + $tinfo->{exp_fail}= 1; last; } } diff --git a/mysql-test/lib/v1/incompatible.tests b/mysql-test/lib/v1/incompatible.tests new file mode 100644 index 00000000000..fefdad9ce4c --- /dev/null +++ b/mysql-test/lib/v1/incompatible.tests @@ -0,0 +1,6 @@ +# This file lists tests that cannot run in MTR v1 for some reason. +# They will be skipped. +# Any text following white space after full test name is ignored +# Only exact test names can be used, no regexp. + +main.fulltext_plugin # Refers to $SIMPLE_PARSER_OPT which is not set diff --git a/mysql-test/lib/v1/mtr_cases.pl b/mysql-test/lib/v1/mtr_cases.pl index 4d7b1f4ec70..288e8c22b44 100644 --- a/mysql-test/lib/v1/mtr_cases.pl +++ b/mysql-test/lib/v1/mtr_cases.pl @@ -32,6 +32,7 @@ sub mtr_options_from_test_file($$); my $do_test; my $skip_test; +my %incompatible; sub init_pattern { my ($from, $what)= @_; @@ -47,6 +48,15 @@ sub init_pattern { } +sub collect_incomp_tests { + open (INCOMP, "lib/v1/incompatible.tests"); + while (<INCOMP>) + { + next unless /^\w/; + s/\s.*\n//; # Ignore anything from first white space + $incompatible{$_}= 1; + } +} ############################################################################## # @@ -58,6 +68,8 @@ sub collect_test_cases ($) { $do_test= init_pattern($::opt_do_test, "--do-test"); $skip_test= init_pattern($::opt_skip_test, "--skip-test"); + collect_incomp_tests(); + my $suites= shift; # Semicolon separated list of test suites my $cases = []; # Array of hash @@ -528,6 +540,17 @@ sub collect_one_test_case($$$$$$$$$) { $tinfo->{'component_id'} = $component_id; push(@$cases, $tinfo); + # Remove "combinations" part of test name + my $test_base_name= $tinfo->{'name'}; + $test_base_name=~ s/\s.*\n//; + + if (exists ($incompatible{$test_base_name})) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Test cannot run in mtr v1"; + return; + } + # ---------------------------------------------------------------------- # Skip some tests but include in list, just mark them to skip # ---------------------------------------------------------------------- @@ -841,7 +864,7 @@ sub collect_one_test_case($$$$$$$$$) { if ( $tinfo->{'innodb_test'} ) { # This is a test that need innodb - if ( $::mysqld_variables{'innodb'} ne "TRUE" ) + if ( $::mysqld_variables{'innodb'} eq "OFF" ) { # innodb is not supported, skip it $tinfo->{'skip'}= 1; diff --git a/mysql-test/mysql-stress-test.pl b/mysql-test/mysql-stress-test.pl index ff2566b1476..8b94ba1404d 100755 --- a/mysql-test/mysql-stress-test.pl +++ b/mysql-test/mysql-stress-test.pl @@ -14,17 +14,16 @@ # # Design of stress script should allow one: # -# - To stress test the mysqltest binary test engine. -# - To stress test the regular test suite and any additional test suites -# (such as mysql-test-extra-5.0). -# - To specify files with lists of tests both for initialization of -# stress db and for further testing itself. -# - To define the number of threads to be concurrently used in testing. -# - To define limitations for the test run. such as the number of tests or -# loops for execution or duration of testing, delay between test -# executions, and so forth. -# - To get a readable log file that can be used for identification of -# errors that occur during testing. +# - to use for stress testing mysqltest binary as test engine +# - to use for stress testing both regular test suite and any +# additional test suites (e.g. mysql-test-extra-5.0) +# - to specify files with lists of tests both for initialization of +# stress db and for further testing itself +# - to define number of threads that will be concurrently used in testing +# - to define limitations for test run. e.g. number of tests or loops +# for execution or duration of testing, delay between test executions, etc. +# - to get readable log file which can be used for identification of +# errors arose during testing # # Basic scenarios: # @@ -58,6 +57,8 @@ # to reproduce and debug errors that was found in continued stress # testing # +# 2009-01-28 OBN Additions and modifications per WL#4685 +# ######################################################################## use Config; @@ -114,13 +115,15 @@ $opt_stress_mode="random"; $opt_loop_count=0; $opt_test_count=0; $opt_test_duration=0; -$opt_abort_on_error=0; +# OBN: Changing abort-on-error default to -1 (for WL-4626/4685): -1 means no abort +$opt_abort_on_error=-1; $opt_sleep_time = 0; $opt_threads=1; $pid_file="mysql_stress_test.pid"; $opt_mysqltest= ($^O =~ /mswin32/i) ? "mysqltest.exe" : "mysqltest"; $opt_check_tests_file=""; -@mysqltest_args=("--silent", "-v", "--skip-safemalloc"); +# OBM adding a setting for 'max-connect-retries=7' the default of 500 is to high +@mysqltest_args=("--silent", "-v", "--skip-safemalloc", "--max-connect-retries=7"); # Client ip address $client_ip=inet_ntoa((gethostbyname(hostname()))[4]); @@ -133,24 +136,31 @@ $client_ip=~ s/\.//g; # # S1 - Critical errors - cause immediately abort of testing. These errors # could be caused by server crash or impossibility -# of test execution +# of test execution. # # S2 - Serious errors - these errors are bugs for sure as it knowns that # they shouldn't appear during stress testing # -# S3 - Non-seriuos errros - these errors could be caused by fact that +# S3 - Unknown errors - Errors were returned but we don't know what they are +# so script can't determine if they are OK or not +# +# S4 - Non-seriuos errros - these errors could be caused by fact that # we execute simultaneously statements that # affect tests executed by other threads %error_strings = ( 'Failed in mysql_real_connect()' => S1, + 'Can\'t connect' => S1, 'not found (Errcode: 2)' => S1 ); %error_codes = ( 1012 => S2, 1015 => S2, 1021 => S2, 1027 => S2, 1037 => S2, 1038 => S2, 1039 => S2, 1040 => S2, 1046 => S2, - 1180 => S2, 1181 => S2, 1203 => S2, - 1205 => S2, 1206 => S2, 1207 => S2, - 1223 => S2, 2013 => S1); + 1053 => S2, 1180 => S2, 1181 => S2, + 1203 => S2, 1205 => S4, 1206 => S2, + 1207 => S2, 1213 => S4, 1223 => S2, + 2002 => S1, 2003 => S1, 2006 => S1, + 2013 => S1 + ); share(%test_counters); %test_counters=( loop_count => 0, test_count=>0); @@ -158,6 +168,35 @@ share(%test_counters); share($exiting); $exiting=0; +# OBN Code and 'set_exit_code' function added by ES to set an exit code based on the error category returned +# in combination with the --abort-on-error value see WL#4685) +use constant ABORT_MAKEWEIGHT => 20; +share($gExitCode); +$gExitCode = 0; # global exit code +sub set_exit_code { + my $severity = shift; + my $code = 0; + if ( $severity =~ /^S(\d+)/ ) { + $severity = $1; + $code = 11 - $severity; # S1=10, S2=9, ... -- as per WL + } + else { + # we know how we call the sub: severity should be S<num>; so, we should never be here... + print STDERR "Unknown severity format: $severity; setting to S1\n"; + $severity = 1; + } + $abort = 0; + if ( $severity <= $opt_abort_on_error ) { + # the test finished with a failure severe enough to abort. We are adding the 'abort flag' to the exit code + $code += ABORT_MAKEWEIGHT; + # but are not exiting just yet -- we need to update global exit code first + $abort = 1; + } + lock $gExitCode; # we can use lock here because the script uses threads anyway + $gExitCode = $code if $code > $gExitCode; + kill INT, $$ if $abort; # this is just a way to call sig_INT_handler: it will set exiting flag, which should do the rest +} + share($test_counters_lock); $test_counters_lock=0; share($log_file_lock); @@ -176,7 +215,8 @@ GetOptions("server-host=s", "server-logs-dir=s", "server-port=s", "threads=s", "sleep-time=s", "loop-count=i", "test-count=i", "test-duration=i", "test-suffix=s", "check-tests-file", "verbose", "log-error-details", "cleanup", "mysqltest=s", - "abort-on-error", "help") || usage(); + # OBN: (changing 'abort-on-error' to numberic for WL-4626/4685) + "abort-on-error=i" => \$opt_abort_on_error, "help") || usage(); usage() if ($opt_help); @@ -563,7 +603,15 @@ EOF if ($opt_test_duration) { - sleep($opt_test_duration); + # OBN - At this point we need to wait for the duration of the test, hoever + # we need to be able to quit if an 'abort-on-error' condition has happend + # with one of the children (WL#4685). Using solution by ES and replacing + # the 'sleep' command with a loop checking the abort condition every second + + foreach ( 1..$opt_test_duration ) { + last if $exiting; + sleep 1; + } kill INT, $$; #Interrupt child threads } @@ -580,6 +628,8 @@ EOF print "EXIT\n"; } +exit $gExitCode; # ES WL#4685: script should return a meaningful exit code + sub test_init { my ($env)=@_; @@ -681,7 +731,9 @@ sub test_execute { if (!exists($error_codes{$err_code})) { - $severity="S3"; + # OBN Changing severity level to S4 from S3 as S3 now reserved + # for the case where the error is unknown (for WL#4626/4685 + $severity="S4"; $err_code=0; } else @@ -734,6 +786,7 @@ sub test_execute { push @{$env->{test_status}}, "Severity $severity: $total"; $env->{errors}->{total}=+$total; + set_exit_code($severity); } } @@ -748,18 +801,20 @@ sub test_execute log_session_errors($env, $test_file); - if (!$exiting && ($signal_num == 2 || $signal_num == 15 || - ($opt_abort_on_error && $env->{errors}->{S1} > 0))) + #OBN Removing the case of S1 and abort-on-error as that is now set + # inside the set_exit_code function (for WL#4626/4685) + #if (!$exiting && ($signal_num == 2 || $signal_num == 15 || + # ($opt_abort_on_error && $env->{errors}->{S1} > 0))) + if (!$exiting && ($signal_num == 2 || $signal_num == 15)) { - #mysqltest was interrupted with INT or TERM signals or test was - #ran with --abort-on-error option and we got errors with severity S1 + #mysqltest was interrupted with INT or TERM signals #so we assume that we should cancel testing and exit $exiting=1; + # OBN - Adjusted text to exclude case of S1 and abort-on-error that + # was mentioned (for WL#4626/4685) print STDERR<<EOF; WARNING: - mysqltest was interrupted with INT or TERM signals or test was - ran with --abort-on-error option and we got errors with severity S1 - (test cann't connect to the server or server crashed) so we assume that + mysqltest was interrupted with INT or TERM signals so we assume that we should cancel testing and exit. Please check log file for this thread in $stress_log_file or inspect below output of the last test case executed with mysqltest to @@ -840,12 +895,23 @@ LOOP: $client_env{test_count}."]:". " TID ".$client_env{thread_id}. " test: '$test_name' ". - " Errors: ".join(" ",@{$client_env{test_status}}),"\n"; - print "\n"; + " Errors: ".join(" ",@{$client_env{test_status}}). + ( $exiting ? " (thread aborting)" : "" )."\n"; } - sleep($opt_sleep_time) if($opt_sleep_time); - + # OBN - At this point we need to wait until the 'wait' time between test + # executions passes (in case it is specifed) passes, hoever we need + # to be able to quit and break out of the test if an 'abort-on-error' + # condition has happend with one of the other children (WL#4685). + # Using solution by ES and replacing the 'sleep' command with a loop + # checking the abort condition every second + + if ( $opt_sleep_time ) { + foreach ( 1..$opt_sleep_time ) { + last if $exiting; + sleep 1; + } + } } } @@ -1119,6 +1185,9 @@ mysql-stress-test.pl --stress-basedir=<dir> --stress-suite-basedir=<dir> --serve --cleanup Force to clean up working directory (specified with --stress-basedir) +--abort-on-error=<number> + Causes the script to abort if an error with severity <= number was encounterd + --log-error-details Enable errors details in the global error log file. (Default: off) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 526077a7de1..fa9b9762592 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -150,7 +150,7 @@ our @opt_extra_mysqltest_opt; my $opt_compress; my $opt_ssl; my $opt_skip_ssl; -my $opt_ssl_supported; +our $opt_ssl_supported; my $opt_ps_protocol; my $opt_sp_protocol; my $opt_cursor_protocol; @@ -216,6 +216,7 @@ sub check_timeout { return $opt_testcase_timeout * 6; }; my $opt_start; my $opt_start_dirty; +my $start_only; my $opt_wait_all; my $opt_repeat= 1; my $opt_retry= 3; @@ -339,7 +340,8 @@ sub main { for my $limit (2000, 1500, 1000, 500){ $opt_parallel-- if ($sys_info->min_bogomips() < $limit); } - $opt_parallel= 8 if ($opt_parallel > 8); + my $max_par= $ENV{MTR_MAX_PARALLEL} || 8; + $opt_parallel= $max_par if ($opt_parallel > $max_par); $opt_parallel= $num_tests if ($opt_parallel > $num_tests); $opt_parallel= 1 if (IS_WINDOWS and $sys_info->isvm()); $opt_parallel= 1 if ($opt_parallel < 1); @@ -547,7 +549,8 @@ sub run_test_server ($$$) { } } $num_saved_datadir++; - $num_failed_test++ unless $result->{retries}; + $num_failed_test++ unless ($result->{retries} || + $result->{exp_fail}); $test_failure= 1; if ( !$opt_force ) { @@ -1052,6 +1055,9 @@ sub command_line_setup { if ( $opt_experimental ) { + # $^O on Windows considered not generic enough + my $plat= (IS_WINDOWS) ? 'windows' : $^O; + # read the list of experimental test cases from the file specified on # the command line open(FILE, "<", $opt_experimental) or mtr_error("Can't read experimental file: $opt_experimental"); @@ -1062,6 +1068,15 @@ sub command_line_setup { # remove comments (# foo) at the beginning of the line, or after a # blank at the end of the line s/( +|^)#.*$//; + # If @ platform specifier given, use this entry only if it contains + # @<platform> or @!<xxx> where xxx != platform + if (/\@.*/) + { + next if (/\@!$plat/); + next unless (/\@$plat/ or /\@!/); + # Then remove @ and everything after it + s/\@.*$//; + } # remove whitespace s/^ +//; s/ +$//; @@ -1321,6 +1336,21 @@ sub command_line_setup { { mtr_error("Can't use --extern when using debugger"); } + # Set one week timeout (check-testcase timeout will be 1/10th) + $opt_testcase_timeout= 7 * 24 * 60; + $opt_suite_timeout= 7 * 24 * 60; + # One day to shutdown + $opt_shutdown_timeout= 24 * 60; + # One day for PID file creation (this is given in seconds not minutes) + $opt_start_timeout= 24 * 60 * 60; + } + + # -------------------------------------------------------------------------- + # Modified behavior with --start options + # -------------------------------------------------------------------------- + if ($opt_start or $opt_start_dirty) { + collect_option ('quick-collect', 1); + $start_only= 1; } if ($opt_debug) { @@ -1334,7 +1364,7 @@ sub command_line_setup { # Check use of wait-all # -------------------------------------------------------------------------- - if ($opt_wait_all && ! ($opt_start_dirty || $opt_start)) + if ($opt_wait_all && ! $start_only) { mtr_error("--wait-all can only be used with --start or --start-dirty"); } @@ -1394,6 +1424,9 @@ sub command_line_setup { push(@valgrind_args, @default_valgrind_args) unless @valgrind_args; + # Make valgrind run in quiet mode so it only print errors + push(@valgrind_args, "--quiet" ); + mtr_report("Running valgrind with options \"", join(" ", @valgrind_args), "\""); } @@ -1609,6 +1642,10 @@ sub collect_mysqld_features_from_running_server () } } + # "Convert" innodb flag + $mysqld_variables{'innodb'}= "ON" + if ($mysqld_variables{'have_innodb'} eq "YES"); + # Parse version my $version_str= $mysqld_variables{'version'}; if ( $version_str =~ /^([0-9]*)\.([0-9]*)\.([0-9]*)/ ) @@ -1909,11 +1946,11 @@ sub environment_setup { # -------------------------------------------------------------------------- # Add the path where mysqld will find ha_example.so # -------------------------------------------------------------------------- - if ($mysql_version_id >= 50100 && !(IS_WINDOWS && $opt_embedded_server)) { + if ($mysql_version_id >= 50100) { my $plugin_filename; if (IS_WINDOWS) { - $plugin_filename = "ha_example.dll"; + $plugin_filename = "ha_example.dll"; } else { @@ -1930,7 +1967,7 @@ sub environment_setup { ($lib_example_plugin ? dirname($lib_example_plugin) : ""); $ENV{'HA_EXAMPLE_SO'}="'".$plugin_filename."'"; - $ENV{'EXAMPLE_PLUGIN_LOAD'}="--plugin_load=;EXAMPLE=".$plugin_filename.";"; + $ENV{'EXAMPLE_PLUGIN_LOAD'}="--plugin_load=EXAMPLE=".$plugin_filename; } # ---------------------------------------------------- @@ -3004,7 +3041,7 @@ sub run_testcase_check_skip_test($) if ( $tinfo->{'skip'} ) { - mtr_report_test_skipped($tinfo); + mtr_report_test_skipped($tinfo) unless $start_only; return 1; } @@ -3174,7 +3211,8 @@ test case was executed:\n"; # Unknown process returned, most likley a crash, abort everything $tinfo->{comment}= "The server $proc crashed while running ". - "'check testcase $mode test'"; + "'check testcase $mode test'". + get_log_from_proc($proc, $tinfo->{name}); $result= 3; } @@ -3292,7 +3330,8 @@ sub run_on_all($$) else { # Unknown process returned, most likley a crash, abort everything $tinfo->{comment}.= - "The server $proc crashed while running '$run'"; + "The server $proc crashed while running '$run'". + get_log_from_proc($proc, $tinfo->{name}); } # Kill any check processes still running @@ -3407,6 +3446,12 @@ sub run_testcase ($$) { mtr_verbose("Running test:", $tinfo->{name}); + # Allow only alpanumerics pluss _ - + . in combination names + my $combination= $tinfo->{combination}; + if ($combination && $combination !~ /^\w[-\w\.\+]+$/) + { + mtr_error("Combination '$combination' contains illegal characters"); + } # ------------------------------------------------------- # Init variables that can change between each test case # ------------------------------------------------------- @@ -3501,9 +3546,16 @@ sub run_testcase ($$) { # server exits # ---------------------------------------------------------------------- - if ( $opt_start or $opt_start_dirty ) + if ( $start_only ) { mtr_print("\nStarted", started(all_servers())); + mtr_print("Using config for test", $tinfo->{name}); + mtr_print("Port and socket path for server(s):"); + foreach my $mysqld ( mysqlds() ) + { + mtr_print ($mysqld->name() . " " . $mysqld->value('port') . + " " . $mysqld->value('socket')); + } mtr_print("Waiting for server(s) to exit..."); if ( $opt_wait_all ) { My::SafeProcess->wait_all(); @@ -3597,7 +3649,7 @@ sub run_testcase ($$) { my $check_res; if ( restart_forced_by_test() ) { - stop_all_servers(); + stop_all_servers($opt_shutdown_timeout); } elsif ( $opt_check_testcases and $check_res= check_testcase($tinfo, "after")) @@ -3614,7 +3666,7 @@ sub run_testcase ($$) { # test. } else { # Not checking warnings, so can do a hard shutdown. - stop_all_servers(); + stop_all_servers($opt_shutdown_timeout); } mtr_report("Resuming tests...\n"); } @@ -3696,7 +3748,8 @@ sub run_testcase ($$) { { # Server failed, probably crashed $tinfo->{comment}= - "Server $proc failed during test run"; + "Server $proc failed during test run" . + get_log_from_proc($proc, $tinfo->{name}); # ---------------------------------------------------- # It's not mysqltest that has exited, kill it @@ -3809,16 +3862,15 @@ sub pre_write_errorlog { } } +# Extract server log from after the last occurrence of named test +# Return as an array of lines # -# Perform a rough examination of the servers -# error log and write all lines that look -# suspicious into $error_log.warnings -# -sub extract_warning_lines ($) { - my ($error_log) = @_; + +sub extract_server_log ($$) { + my ($error_log, $tname) = @_; # Open the servers .err log file and read all lines - # belonging to current tets into @lines + # belonging to current test into @lines my $Ferr = IO::File->new($error_log) or return []; my $last_pos= $last_warning_position->{$error_log}{seek_pos}; @@ -3849,8 +3901,37 @@ sub extract_warning_lines ($) { } } } + return @lines; +} + +# Get log from server identified from its $proc object, from named test +# Return as a single string +# + +sub get_log_from_proc ($$) { + my ($proc, $name)= @_; + my $srv_log= ""; + + foreach my $mysqld (mysqlds()) { + if ($mysqld->{proc} eq $proc) { + my @srv_lines= extract_server_log($mysqld->value('#log-error'), $name); + $srv_log= "\nServer log from this test:\n" . join ("", @srv_lines); + last; + } + } + return $srv_log; +} - # Write all suspicious lines to $error_log.warnings file +# Perform a rough examination of the servers +# error log and write all lines that look +# suspicious into $error_log.warnings +# +sub extract_warning_lines ($$) { + my ($error_log, $tname) = @_; + + my @lines= extract_server_log($error_log, $tname); + +# Write all suspicious lines to $error_log.warnings file my $warning_log = "$error_log.warnings"; my $Fwarn = IO::File->new($warning_log, "w") or die("Could not open file '$warning_log' for writing: $!"); @@ -3858,16 +3939,9 @@ sub extract_warning_lines ($) { my @patterns = ( - # The patterns for detection of [Warning] and [ERROR] - # in the server log files have been faulty for a longer period - # and correcting them shows a few additional harmless warnings. - # Thus those patterns are temporarily removed from the list - # of patterns. For more info see BUG#42408 - # qr/^Warning:|mysqld: Warning|\[Warning\]/, - # qr/^Error:|\[ERROR\]/, - qr/^Warning:|mysqld: Warning/, - qr/^Error:/, - qr/^==.* at 0x/, + qr/^Warning:|mysqld: Warning|\[Warning\]/, + qr/^Error:|\[ERROR\]/, + qr/^==\d*==/, # valgrind errors qr/InnoDB: Warning|InnoDB: Error/, qr/^safe_mutex:|allocated at line/, qr/missing DBUG_RETURN/, @@ -3886,6 +3960,7 @@ sub extract_warning_lines ($) { # Perl code. my @antipatterns = ( + qr/error .*connecting to master/, qr/InnoDB: Error: in ALTER TABLE `test`.`t[12]`/, qr/InnoDB: Error: table `test`.`t[12]` does not exist in the InnoDB internal/, ); @@ -3933,7 +4008,7 @@ sub start_check_warnings ($$) { my $log_error= $mysqld->value('#log-error'); # To be communicated to the test $ENV{MTR_LOG_ERROR}= $log_error; - extract_warning_lines($log_error); + extract_warning_lines($log_error, $tinfo->{name}); my $args; mtr_init_args(\$args); @@ -3980,7 +4055,7 @@ sub start_check_warnings ($$) { # # Loop through our list of processes and check the error log -# for unexepcted errors and warnings +# for unexpected errors and warnings # sub check_warnings ($) { my ($tinfo)= @_; @@ -4067,7 +4142,8 @@ sub check_warnings ($) { else { # Unknown process returned, most likley a crash, abort everything $tinfo->{comment}= - "The server $proc crashed while running 'check warnings'"; + "The server $proc crashed while running 'check warnings'". + get_log_from_proc($proc, $tinfo->{name}); $result= 3; } @@ -4083,13 +4159,15 @@ sub check_warnings ($) { } # Check for warnings generated during shutdown of a mysqld server. -# If any, report them to master server, and return true; else just return false. +# If any, report them to master server, and return true; else just return +# false. + sub check_warnings_post_shutdown { my ($server_socket)= @_; my $testname_hash= { }; foreach my $mysqld ( mysqlds()) { - my $testlist= extract_warning_lines($mysqld->value('#log-error')); + my $testlist= extract_warning_lines($mysqld->value('#log-error'), ""); $testname_hash->{$_}= 1 for @$testlist; } my @warning_tests= keys(%$testname_hash); @@ -4343,6 +4421,7 @@ sub mysqld_stop { mtr_init_args(\$args); mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--character-sets-dir=%s", $mysqld->value('character-sets-dir')); mtr_add_arg($args, "--user=%s", $opt_user); mtr_add_arg($args, "--password="); mtr_add_arg($args, "--port=%d", $mysqld->value('port')); @@ -4392,7 +4471,7 @@ sub mysqld_arguments ($$$) { if (!using_extern() and $mysql_version_id >= 50106 ) { - # Turn on logging to bothe tables and file + # Turn on logging to file and tables mtr_add_arg($args, "%s--log-output=table,file"); } @@ -4555,7 +4634,8 @@ sub mysqld_start ($$) { $opt_start_timeout, $mysqld->{'proc'})) { - mtr_error("Failed to start mysqld $mysqld->name()"); + my $mname= $mysqld->name(); + mtr_error("Failed to start mysqld $mname with command $exe"); } # Remember options used when starting @@ -4566,11 +4646,12 @@ sub mysqld_start ($$) { sub stop_all_servers () { + my $shutdown_timeout = $_[0] or 0; mtr_verbose("Stopping all servers..."); # Kill all started servers - My::SafeProcess::shutdown(0, # shutdown timeout 0 => kill + My::SafeProcess::shutdown($shutdown_timeout, started(all_servers())); # Remove pidfiles @@ -4940,7 +5021,8 @@ sub start_servers($) { my $logfile= $mysqld->value('#log-error'); if ( defined $logfile and -f $logfile ) { - $tinfo->{logfile}= mtr_fromfile($logfile); + my @srv_lines= extract_server_log($logfile, $tinfo->{name}); + $tinfo->{logfile}= "Server log is:\n" . join ("", @srv_lines); } else { @@ -5369,7 +5451,6 @@ sub valgrind_arguments { else { mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option - mtr_add_arg($args, "--alignment=8"); mtr_add_arg($args, "--leak-check=yes"); mtr_add_arg($args, "--num-callers=16"); mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir) @@ -5468,7 +5549,7 @@ Options to control what test suites or cases to run staging-run Run a limited number of tests (no slow tests). Used for running staging trees with valgrind. enable-disabled Run also tests marked as disabled - print_testcases Don't run the tests but print details about all the + print-testcases Don't run the tests but print details about all the selected tests, in the order they would be run. Options that specify ports diff --git a/mysql-test/r/almost_full.result b/mysql-test/r/almost_full.result index eb28f12fa51..b2d7092aa51 100644 --- a/mysql-test/r/almost_full.result +++ b/mysql-test/r/almost_full.result @@ -1,3 +1,4 @@ +call mtr.add_suppression("The table 't1' is full"); drop table if exists t1; set global myisam_data_pointer_size=2; CREATE TABLE t1 (a int auto_increment primary key not null, b longtext) ENGINE=MyISAM; diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index b1e13f0f879..1d41ad3cbf5 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -1175,4 +1175,74 @@ a 42 DROP TABLE t1; SET @@sql_mode=@save_sql_mode; +# +# Bug#45567: Fast ALTER TABLE broken for enum and set +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a ENUM('a1','a2')); +INSERT INTO t1 VALUES ('a1'),('a2'); +# No copy: No modification +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# No copy: Add new enumeration to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a3'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# Copy: Modify and add new to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','xx','a5'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# Copy: Remove from the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','xx'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# Copy: Add new enumeration +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a0','xx'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# No copy: Add new enumerations to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a0','xx','a5','a6'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +DROP TABLE t1; +CREATE TABLE t1 (a SET('a1','a2')); +INSERT INTO t1 VALUES ('a1'),('a2'); +# No copy: No modification +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# No copy: Add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a3'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# Copy: Modify and add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','xx','a5'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# Copy: Remove from the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','xx'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# Copy: Add new member +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +# No copy: Add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx','a5','a6'); +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +# Copy: Numerical incrase (pack lenght) +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx','a5','a6','a7','a8','a9','a10'); +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 +DROP TABLE t1; +CREATE TABLE t1 (f1 TIMESTAMP NULL DEFAULT NULL, +f2 INT(11) DEFAULT NULL) ENGINE=MYISAM DEFAULT CHARSET=utf8; +INSERT INTO t1 VALUES (NULL, NULL), ("2009-10-09 11:46:19", 2); +this should affect no rows as there is no real change +ALTER TABLE t1 CHANGE COLUMN f1 f1_no_real_change TIMESTAMP NULL DEFAULT NULL; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/r/analyse.result b/mysql-test/r/analyse.result index 6eaa8731dc6..1820782d2f8 100644 --- a/mysql-test/r/analyse.result +++ b/mysql-test/r/analyse.result @@ -19,81 +19,10 @@ test.t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL test.t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL test.t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL create table t2 select * from t1 procedure analyse(); -select * from t2; -Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -test.t1.i 1 7 1 1 0 0 4.0000 2.2361 ENUM('1','3','5','7') NOT NULL -test.t1.j 2 8 1 1 0 0 5.0000 2.2361 ENUM('2','4','6','8') NOT NULL -test.t1.empty_string 0 0 4 0 0.0000 NULL CHAR(0) NOT NULL -test.t1.bool N Y 1 1 0 0 1.0000 NULL ENUM('N','Y') NOT NULL -test.t1.d 2002-03-03 2002-03-05 10 10 0 0 10.0000 NULL ENUM('2002-03-03','2002-03-04','2002-03-05') NOT NULL -drop table t1,t2; +ERROR HY000: Incorrect usage of PROCEDURE and non-SELECT +drop table t1; EXPLAIN SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(); ERROR HY000: Incorrect usage of PROCEDURE and subquery -create table t1 (a int not null); -create table t2 select * from t1 where 0=1 procedure analyse(); -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `Field_name` varbinary(255) NOT NULL DEFAULT '', - `Min_value` varbinary(255) DEFAULT NULL, - `Max_value` varbinary(255) DEFAULT NULL, - `Min_length` bigint(11) NOT NULL DEFAULT '0', - `Max_length` bigint(11) NOT NULL DEFAULT '0', - `Empties_or_zeros` bigint(11) NOT NULL DEFAULT '0', - `Nulls` bigint(11) NOT NULL DEFAULT '0', - `Avg_value_or_avg_length` varbinary(255) NOT NULL DEFAULT '', - `Std` varbinary(255) DEFAULT NULL, - `Optimal_fieldtype` varbinary(64) NOT NULL DEFAULT '' -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -select * from t1 where 0=1 procedure analyse(); -Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -insert into t1 values(1); -drop table t2; -create table t2 select * from t1 where 0=1 procedure analyse(); -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `Field_name` varbinary(255) NOT NULL DEFAULT '', - `Min_value` varbinary(255) DEFAULT NULL, - `Max_value` varbinary(255) DEFAULT NULL, - `Min_length` bigint(11) NOT NULL DEFAULT '0', - `Max_length` bigint(11) NOT NULL DEFAULT '0', - `Empties_or_zeros` bigint(11) NOT NULL DEFAULT '0', - `Nulls` bigint(11) NOT NULL DEFAULT '0', - `Avg_value_or_avg_length` varbinary(255) NOT NULL DEFAULT '', - `Std` varbinary(255) DEFAULT NULL, - `Optimal_fieldtype` varbinary(64) NOT NULL DEFAULT '' -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -select * from t2; -Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -insert into t2 select * from t1 procedure analyse(); -select * from t2; -Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -test.t1.a 1 1 1 1 0 0 1.0000 0.0000 ENUM('1') NOT NULL -insert into t1 values(2); -drop table t2; -create table t2 select * from t1 where 0=1 procedure analyse(); -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `Field_name` varbinary(255) NOT NULL DEFAULT '', - `Min_value` varbinary(255) DEFAULT NULL, - `Max_value` varbinary(255) DEFAULT NULL, - `Min_length` bigint(11) NOT NULL DEFAULT '0', - `Max_length` bigint(11) NOT NULL DEFAULT '0', - `Empties_or_zeros` bigint(11) NOT NULL DEFAULT '0', - `Nulls` bigint(11) NOT NULL DEFAULT '0', - `Avg_value_or_avg_length` varbinary(255) NOT NULL DEFAULT '', - `Std` varbinary(255) DEFAULT NULL, - `Optimal_fieldtype` varbinary(64) NOT NULL DEFAULT '' -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -select * from t2; -Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -insert into t2 select * from t1 procedure analyse(); -select * from t2; -Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype -test.t1.a 1 2 1 1 0 0 1.5000 0.5000 ENUM('1','2') NOT NULL -drop table t1,t2; create table t1 (v varchar(128)); insert into t1 values ('abc'),('abc\'def\\hij\"klm\0opq'),('\''),('\"'),('\\'),('a\0'),('b\''),('c\"'),('d\\'),('\'b'),('\"c'),('\\d'),('a\0\0\0b'),('a\'\'\'\'b'),('a\"\"\"\"b'),('a\\\\\\\\b'),('\'\0\\\"'),('\'\''),('\"\"'),('\\\\'),('The\ZEnd'); select * from t1 procedure analyse(); @@ -157,3 +86,40 @@ SELECT * FROM (SELECT * FROM t1) d PROCEDURE ANALYSE(); ERROR HY000: Incorrect usage of PROCEDURE and subquery DROP TABLE t1; End of 4.1 tests +# +# Bug #48293: crash with procedure analyse, view with > 10 columns, +# having clause... +# +CREATE TABLE t1(a INT, b INT, c INT, d INT, e INT, +f INT, g INT, h INT, i INT, j INT,k INT); +INSERT INTO t1 VALUES (),(); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +#should have a derived table +EXPLAIN SELECT * FROM v1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 +2 DERIVED t1 ALL NULL NULL NULL NULL 2 +#should not crash +SELECT * FROM v1 PROCEDURE analyse(); +ERROR HY000: Incorrect usage of PROCEDURE and view +#should not crash +SELECT * FROM t1 a, v1, t1 b PROCEDURE analyse(); +ERROR HY000: Incorrect usage of PROCEDURE and view +#should not crash +SELECT * FROM (SELECT * FROM t1 having a > 1) x PROCEDURE analyse(); +ERROR HY000: Incorrect usage of PROCEDURE and subquery +#should not crash +SELECT * FROM t1 a, (SELECT * FROM t1 having a > 1) x, t1 b PROCEDURE analyse(); +ERROR HY000: Incorrect usage of PROCEDURE and subquery +#should not crash +SELECT 1 FROM t1 group by a having a > 1 order by 1 PROCEDURE analyse(); +ERROR HY000: Can't use ORDER clause with this procedure +DROP VIEW v1; +DROP TABLE t1; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1),(2); +# should not crash +CREATE TABLE t2 SELECT 1 FROM t1, t1 t3 GROUP BY t3.a PROCEDURE ANALYSE(); +ERROR HY000: Incorrect usage of PROCEDURE and non-SELECT +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index 8c26ea1ff82..e865d775c6a 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -12695,3 +12695,25 @@ a b 1 NULL 2 NULL DROP TABLE t1; +CREATE TABLE t1(a INT, b BLOB) ENGINE=archive; +SELECT DATA_LENGTH, AVG_ROW_LENGTH FROM +INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test'; +DATA_LENGTH AVG_ROW_LENGTH +8666 15 +INSERT INTO t1 VALUES(1, 'sampleblob1'),(2, 'sampleblob2'); +SELECT DATA_LENGTH, AVG_ROW_LENGTH FROM +INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test'; +DATA_LENGTH AVG_ROW_LENGTH +8700 4350 +DROP TABLE t1; +SET @save_join_buffer_size= @@join_buffer_size; +SET @@join_buffer_size= 8228; +CREATE TABLE t1(a CHAR(255)) ENGINE=archive; +INSERT INTO t1 VALUES('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'), +('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'), +('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); +SELECT COUNT(t1.a) FROM t1, t1 a, t1 b, t1 c, t1 d, t1 e; +COUNT(t1.a) +729 +DROP TABLE t1; +SET @@join_buffer_size= @save_join_buffer_size; diff --git a/mysql-test/r/bug40113.result b/mysql-test/r/bug40113.result deleted file mode 100644 index 289037a3f35..00000000000 --- a/mysql-test/r/bug40113.result +++ /dev/null @@ -1,29 +0,0 @@ -# -# Bug #40113: Embedded SELECT inside UPDATE or DELETE can timeout -# without error -# -CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b)) ENGINE=InnoDB; -INSERT INTO t1 (a,b) VALUES (1070109,99); -CREATE TABLE t2 (b int, a int, PRIMARY KEY (b)) ENGINE=InnoDB; -INSERT INTO t2 (b,a) VALUES (7,1070109); -SELECT * FROM t1; -a b -1070109 99 -BEGIN; -SELECT b FROM t2 WHERE b=7 FOR UPDATE; -b -7 -BEGIN; -SELECT b FROM t2 WHERE b=7 FOR UPDATE; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -INSERT INTO t1 (a) VALUES ((SELECT a FROM t2 WHERE b=7)); -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -UPDATE t1 SET a='7000000' WHERE a=(SELECT a FROM t2 WHERE b=7); -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -DELETE FROM t1 WHERE a=(SELECT a FROM t2 WHERE b=7); -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -SELECT * FROM t1; -a b -1070109 99 -DROP TABLE t2, t1; -End of 5.0 tests diff --git a/mysql-test/r/bug46080.result b/mysql-test/r/bug46080.result index 18c7c22829a..2173768cdad 100644 --- a/mysql-test/r/bug46080.result +++ b/mysql-test/r/bug46080.result @@ -2,6 +2,8 @@ # Bug #46080: group_concat(... order by) crashes server when # sort_buffer_size cannot allocate # +call mtr.add_suppression("Out of memory at line .*, 'my_alloc.c'"); +call mtr.add_suppression("needed .* byte .*k., memory in use: .* bytes .*k"); CREATE TABLE t1(a CHAR(255)); INSERT INTO t1 VALUES ('a'); SET @@SESSION.sort_buffer_size=5*16*1000000; diff --git a/mysql-test/r/bug46760.result b/mysql-test/r/bug46760.result new file mode 100644 index 00000000000..413df050b10 --- /dev/null +++ b/mysql-test/r/bug46760.result @@ -0,0 +1,43 @@ +# +# Bug#46760: Fast ALTER TABLE no longer works for InnoDB +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +# By using --enable_info and verifying that number of affected +# rows is 0 we check that this ALTER TABLE is really carried +# out as "fast/online" operation, i.e. without full-blown data +# copying. +# +# I.e. info for the below statement should normally look like: +# +# affected rows: 0 +# info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 10; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT '10' +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; +# +# MySQL Bug#39200: optimize table does not recognize +# ROW_FORMAT=COMPRESSED +# +CREATE TABLE t1 (a INT) ROW_FORMAT=compressed; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status Table is already up to date +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED +DROP TABLE t1; +End of 5.1 tests diff --git a/mysql-test/r/case_insensitive_fs.require b/mysql-test/r/case_insensitive_fs.require new file mode 100644 index 00000000000..062ac610ddd --- /dev/null +++ b/mysql-test/r/case_insensitive_fs.require @@ -0,0 +1,2 @@ +Variable_name Value +lower_case_file_system ON diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 88e4bade130..29686d6e023 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1588,6 +1588,19 @@ CREATE TABLE IF NOT EXISTS t2 (a INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY) SELECT a FROM t1; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' DROP TABLE t1, t2; +# +# BUG#46384 - mysqld segfault when trying to create table with same +# name as existing view +# +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t2 VALUES (1),(2),(3); +CREATE VIEW v1 AS SELECT t1.a FROM t1, t2; +CREATE TABLE v1 AS SELECT * FROM t1; +ERROR 42S01: Table 'v1' already exists +DROP VIEW v1; +DROP TABLE t1,t2; End of 5.0 tests CREATE TABLE t1 (a int, b int); insert into t1 values (1,1),(1,2); diff --git a/mysql-test/r/ctype_ldml.result b/mysql-test/r/ctype_ldml.result index 711921eb526..d5585dcfad9 100644 --- a/mysql-test/r/ctype_ldml.result +++ b/mysql-test/r/ctype_ldml.result @@ -41,6 +41,14 @@ efgh efgh ijkl ijkl DROP TABLE t1; # +# Bug#45645 Mysql server close all connection and restart using lower function +# +CREATE TABLE t1 (a VARCHAR(10)) CHARACTER SET utf8 COLLATE utf8_test_ci; +INSERT INTO t1 (a) VALUES ('hello!'); +SELECT * FROM t1 WHERE LOWER(a)=LOWER('N'); +a +DROP TABLE t1; +# # Bug#43827 Server closes connections and restarts # CREATE TABLE t1 (c1 VARCHAR(10) CHARACTER SET utf8 COLLATE utf8_test_ci); @@ -321,3 +329,11 @@ Vv Xx YyÃýỲỳỴỵỶỷỸỹ drop table t1; +Bug#46448 trailing spaces are not ignored when user collation maps space != 0x20 +set names latin1; +show collation like 'latin1_test'; +Collation Charset Id Default Compiled Sortlen +latin1_test latin1 99 Yes 1 +select "foo" = "foo " collate latin1_test; +"foo" = "foo " collate latin1_test +1 diff --git a/mysql-test/r/debug_sync.result b/mysql-test/r/debug_sync.result new file mode 100644 index 00000000000..47e968f79cf --- /dev/null +++ b/mysql-test/r/debug_sync.result @@ -0,0 +1,277 @@ +SET DEBUG_SYNC= 'RESET'; +DROP TABLE IF EXISTS t1; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: '' +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 EXECUTE 2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE 2'; +SET DEBUG_SYNC='p0 SIGNAL s1 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 EXECUTE 2'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 CLEAR'; +SET DEBUG_SYNC='p0 TEST'; +SET DEBUG_SYNC='RESET'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6'; +set debug_sync='p0 signal s1 wait_for s2 execute 2 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2 execute 2'; +set debug_sync='p0 signal s1 wait_for s2 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2'; +set debug_sync='p0 signal s1 execute 2 hit_limit 3'; +set debug_sync='p0 signal s1 execute 2'; +set debug_sync='p0 signal s1 hit_limit 3'; +set debug_sync='p0 signal s1'; +set debug_sync='p0 wait_for s2 timeout 6 execute 2 hit_limit 3'; +set debug_sync='p0 wait_for s2 timeout 6 execute 2'; +set debug_sync='p0 wait_for s2 timeout 6 hit_limit 3'; +set debug_sync='p0 wait_for s2 timeout 6'; +set debug_sync='p0 wait_for s2 execute 2 hit_limit 3'; +set debug_sync='p0 wait_for s2 execute 2'; +set debug_sync='p0 wait_for s2 hit_limit 3'; +set debug_sync='p0 wait_for s2'; +set debug_sync='p0 hit_limit 3'; +set debug_sync='p0 clear'; +set debug_sync='p0 test'; +set debug_sync='reset'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 + EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC=' p0 SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 '; +SET DEBUG_SYNC=' p0 SIGNAL s1 WAIT_FOR s2 '; +SET DEBUG_SYNC=' p0 SIGNAL s1 WAIT_FOR s2 '; +SET DEBUG_SYNC=''; +ERROR 42000: Missing synchronization point name +SET DEBUG_SYNC=' '; +ERROR 42000: Missing synchronization point name +SET DEBUG_SYNC='p0'; +ERROR 42000: Missing action after synchronization point name 'p0' +SET DEBUG_SYNC='p0 EXECUTE 2'; +ERROR 42000: Missing action before EXECUTE +SET DEBUG_SYNC='p0 TIMEOUT 6 EXECUTE 2'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 TIMEOUT 6'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAL' +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 EXECUTE 2'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAL' +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6 EXECUTE 2'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAL' +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAL' +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1 EXECUTE 2'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAL' +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAL' +SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2 EXECUTE 2'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 SIGNAL s1 TIMEOUT 6 EXECUTE 2'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 SIGNAL s1 TIMEOUT 6'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 EXECUTE 2 SIGNAL s1 TIMEOUT 6'; +ERROR 42000: Missing action before EXECUTE +SET DEBUG_SYNC='p0 TIMEOUT 6 SIGNAL s1'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUT' +SET DEBUG_SYNC='p0 EXECUTE 2 TIMEOUT 6 SIGNAL s1'; +ERROR 42000: Missing action before EXECUTE +SET DEBUG_SYNC='p0 CLEAR HIT_LIMIT 3'; +ERROR 42000: Nothing must follow action CLEAR +SET DEBUG_SYNC='CLEAR'; +ERROR 42000: Missing action after synchronization point name 'CLEAR' +SET DEBUG_SYNC='p0 CLEAR p0'; +ERROR 42000: Nothing must follow action CLEAR +SET DEBUG_SYNC='TEST'; +ERROR 42000: Missing action after synchronization point name 'TEST' +SET DEBUG_SYNC='p0 TEST p0'; +ERROR 42000: Nothing must follow action TEST +SET DEBUG_SYNC='p0 RESET'; +ERROR 42000: Illegal or out of order stuff: 'RESET' +SET DEBUG_SYNC='RESET p0'; +ERROR 42000: Illegal or out of order stuff: 'p0' +SET DEBUG_SYNC='p0 RESET p0'; +ERROR 42000: Illegal or out of order stuff: 'RESET' +SET DEBUG_SYNC='p0 SIGNAL '; +ERROR 42000: Missing signal name after action SIGNAL +SET DEBUG_SYNC='p0 WAIT_FOR '; +ERROR 42000: Missing signal name after action WAIT_FOR +SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE '; +ERROR 42000: Missing valid number after EXECUTE +SET DEBUG_SYNCx='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +ERROR HY000: Unknown system variable 'DEBUG_SYNCx' +SET DEBUG_SYNC='p0 SIGNAx s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +ERROR 42000: Illegal or out of order stuff: 'SIGNAx' +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOx s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +ERROR 42000: Illegal or out of order stuff: 'WAIT_FOx' +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUx 0 EXECUTE 2 HIT_LIMIT 3'; +ERROR 42000: Illegal or out of order stuff: 'TIMEOUx' +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTx 2 HIT_LIMIT 3'; +ERROR 42000: Illegal or out of order stuff: 'EXECUTx' +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIx 3'; +ERROR 42000: Illegal or out of order stuff: 'HIT_LIMIx' +SET DEBUG_SYNC='p0 CLEARx'; +ERROR 42000: Illegal or out of order stuff: 'CLEARx' +SET DEBUG_SYNC='p0 TESTx'; +ERROR 42000: Illegal or out of order stuff: 'TESTx' +SET DEBUG_SYNC='RESETx'; +ERROR 42000: Missing action after synchronization point name 'RESETx' +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 0x6 EXECUTE 2 HIT_LIMIT 3'; +ERROR 42000: Missing valid number after TIMEOUT +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 0x2 HIT_LIMIT 3'; +ERROR 42000: Missing valid number after EXECUTE +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 7 EXECUTE 2 HIT_LIMIT 0x3'; +ERROR 42000: Missing valid number after HIT_LIMIT +SET DEBUG_SYNC= 7; +ERROR 42000: Incorrect argument type to variable 'debug_sync' +SET GLOBAL DEBUG_SYNC= 'p0 CLEAR'; +ERROR HY000: Variable 'debug_sync' is a SESSION variable and can't be used with SET GLOBAL +SET @myvar= 'now SIGNAL from_myvar'; +SET DEBUG_SYNC= @myvar; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 'from_myvar' +SET DEBUG_SYNC= LEFT('now SIGNAL from_function_cut_here', 24); +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 'from_function' +SET DEBUG_SYNC= 'now SIGNAL something'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 'something' +SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0'; +Warnings: +Warning #### debug sync point wait timed out +SET DEBUG_SYNC= 'now SIGNAL nothing'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 'nothing' +SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0'; +SET DEBUG_SYNC= 'now SIGNAL something EXECUTE 0'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 'nothing' +SET DEBUG_SYNC= 'now WAIT_FOR anotherthing TIMEOUT 0 EXECUTE 0'; +SET DEBUG_SYNC= 'now HIT_LIMIT 1'; +ERROR HY000: debug sync point hit limit reached +SET DEBUG_SYNC= 'RESET'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: '' +SET DEBUG_SYNC= 'p1abcd SIGNAL s1 EXECUTE 2'; +SET DEBUG_SYNC= 'p2abc SIGNAL s2 EXECUTE 2'; +SET DEBUG_SYNC= 'p9abcdef SIGNAL s9 EXECUTE 2'; +SET DEBUG_SYNC= 'p4a SIGNAL s4 EXECUTE 2'; +SET DEBUG_SYNC= 'p5abcde SIGNAL s5 EXECUTE 2'; +SET DEBUG_SYNC= 'p6ab SIGNAL s6 EXECUTE 2'; +SET DEBUG_SYNC= 'p7 SIGNAL s7 EXECUTE 2'; +SET DEBUG_SYNC= 'p8abcdef SIGNAL s8 EXECUTE 2'; +SET DEBUG_SYNC= 'p3abcdef SIGNAL s3 EXECUTE 2'; +SET DEBUG_SYNC= 'p4a TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's4' +SET DEBUG_SYNC= 'p1abcd TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's1' +SET DEBUG_SYNC= 'p7 TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's7' +SET DEBUG_SYNC= 'p9abcdef TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's9' +SET DEBUG_SYNC= 'p3abcdef TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's3' +SET DEBUG_SYNC= 'p1abcd CLEAR'; +SET DEBUG_SYNC= 'p2abc CLEAR'; +SET DEBUG_SYNC= 'p5abcde CLEAR'; +SET DEBUG_SYNC= 'p6ab CLEAR'; +SET DEBUG_SYNC= 'p8abcdef CLEAR'; +SET DEBUG_SYNC= 'p9abcdef CLEAR'; +SET DEBUG_SYNC= 'p3abcdef CLEAR'; +SET DEBUG_SYNC= 'p4a CLEAR'; +SET DEBUG_SYNC= 'p7 CLEAR'; +SET DEBUG_SYNC= 'p1abcd TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's3' +SET DEBUG_SYNC= 'p7 TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's3' +SET DEBUG_SYNC= 'p9abcdef TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: 's3' +SET DEBUG_SYNC= 'RESET'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +Variable_name Value +debug_sync ON - current signal: '' +CREATE USER mysqltest_1@localhost; +GRANT SUPER ON *.* TO mysqltest_1@localhost; +connection con1, mysqltest_1 +SET DEBUG_SYNC= 'RESET'; +connection default +DROP USER mysqltest_1@localhost; +CREATE USER mysqltest_2@localhost; +GRANT ALL ON *.* TO mysqltest_2@localhost; +REVOKE SUPER ON *.* FROM mysqltest_2@localhost; +connection con1, mysqltest_2 +SET DEBUG_SYNC= 'RESET'; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +connection default +DROP USER mysqltest_2@localhost; +SET DEBUG_SYNC= 'RESET'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INT); +connection con1 +SET DEBUG_SYNC= 'before_lock_tables_takes_lock + SIGNAL opened WAIT_FOR flushed'; +INSERT INTO t1 VALUES(1); +connection default +SET DEBUG_SYNC= 'now WAIT_FOR opened'; +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed'; +FLUSH TABLE t1; +connection con1 +connection default +DROP TABLE t1; +SET DEBUG_SYNC= 'RESET'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INT); +LOCK TABLE t1 WRITE; +connection con1 +SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked EXECUTE 2'; +INSERT INTO t1 VALUES (1); +connection default +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +UNLOCK TABLES; +connection con1 +retrieve INSERT result. +connection default +DROP TABLE t1; +SET DEBUG_SYNC= 'RESET'; diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index eb93c69d960..0124a7da35a 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -279,3 +279,48 @@ ERROR 42000: Incorrect number of arguments for FUNCTION test.f1; expected 0, got DROP TABLE t1; DROP FUNCTION f1; End of 5.0 tests +# +# Bug#46958: Assertion in Diagnostics_area::set_ok_status, trigger, +# merge table +# +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +CREATE TABLE t3 ( a INT ); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); +INSERT INTO t3 VALUES (1), (2); +CREATE TRIGGER tr1 BEFORE DELETE ON t2 +FOR EACH ROW INSERT INTO no_such_table VALUES (1); +DELETE t1, t2, t3 FROM t1, t2, t3; +ERROR 42S02: Table 'test.no_such_table' doesn't exist +SELECT * FROM t1; +a +SELECT * FROM t2; +a +1 +2 +SELECT * FROM t3; +a +1 +2 +DROP TABLE t1, t2, t3; +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +CREATE TABLE t3 ( a INT ); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); +INSERT INTO t3 VALUES (1), (2); +CREATE TRIGGER tr1 AFTER DELETE ON t2 +FOR EACH ROW INSERT INTO no_such_table VALUES (1); +DELETE t1, t2, t3 FROM t1, t2, t3; +ERROR 42S02: Table 'test.no_such_table' doesn't exist +SELECT * FROM t1; +a +SELECT * FROM t2; +a +2 +SELECT * FROM t3; +a +1 +2 +DROP TABLE t1, t2, t3; diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index e0324af8cfd..b1cb70fa43c 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -763,4 +763,34 @@ a b d c 1 2 0 2 1 2 0 3 DROP TABLE t1; +# +# Bug #46159: simple query that never returns +# +SET @old_max_heap_table_size = @@max_heap_table_size; +SET @@max_heap_table_size = 16384; +SET @old_sort_buffer_size = @@sort_buffer_size; +SET @@sort_buffer_size = 32804; +CREATE TABLE t1(c1 int, c2 VARCHAR(20)); +INSERT INTO t1 VALUES (1, '1'), (1, '1'), (2, '2'), (3, '1'), (3, '1'), (4, '4'); +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +SELECT c1, c2, COUNT(*) FROM t1 GROUP BY c1 LIMIT 4; +c1 c2 COUNT(*) +1 1 2 +2 2 1 +3 1 2 +4 4 1 +SELECT DISTINCT c2 FROM t1 GROUP BY c1 HAVING COUNT(*) > 1; +c2 +1 +5 +DROP TABLE t1; +SET @@sort_buffer_size = @old_sort_buffer_size; +SET @@max_heap_table_size = @old_max_heap_table_size; End of 5.1 tests diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index a81ff554ca2..5a1bf1a1290 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -159,6 +159,14 @@ CREATE TABLE t1 (a INT PRIMARY KEY); EXPLAIN EXTENDED SELECT COUNT(a) FROM t1 USE KEY(a); ERROR 42000: Key 'a' doesn't exist in table 't1' DROP TABLE t1; +CREATE TABLE t1(a LONGTEXT); +INSERT INTO t1 VALUES (repeat('a',@@global.max_allowed_packet)); +INSERT INTO t1 VALUES (repeat('b',@@global.max_allowed_packet)); +EXPLAIN SELECT DISTINCT 1 FROM t1, +(SELECT DISTINCTROW a AS away FROM t1 GROUP BY a WITH ROLLUP) as d1 +WHERE t1.a = d1.a; +ERROR 42S22: Unknown column 'd1.a' in 'where clause' +DROP TABLE t1; # # Bug#37870: Usage of uninitialized value caused failed assertion. # @@ -186,4 +194,20 @@ dt 2001-01-01 01:01:01 2001-01-01 01:01:01 drop tables t1, t2; +# +# Bug#48295: +# explain extended crash with subquery and ONLY_FULL_GROUP_BY sql_mode +# +CREATE TABLE t1 (f1 INT); +SELECT @@session.sql_mode INTO @old_sql_mode; +SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; +EXPLAIN EXTENDED SELECT 1 FROM t1 +WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t ); +ERROR 42000: Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause +SHOW WARNINGS; +Level Code Message +Error 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause +Note 1003 select 1 AS `1` from `test`.`t1` where <not>(<exists>(...)) +SET SESSION sql_mode=@old_sql_mode; +DROP TABLE t1; End of 5.1 tests. diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index 3d989ad1730..94147640cde 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -1477,3 +1477,47 @@ COUNT(*) SET SQL_MODE=default; DROP TABLE t1; End of 5.0 tests +# +# BUG#47280 - strange results from count(*) with order by multiple +# columns without where/group +# +# +# Initialize test +# +CREATE TABLE t1 ( +pk INT NOT NULL, +i INT, +PRIMARY KEY (pk) +); +INSERT INTO t1 VALUES (1,11),(2,12),(3,13); +# +# Start test +# All the following queries shall return 1 record +# + +# Masking all correct values {11...13} for column i in this result. +SELECT MAX(pk) as max, i +FROM t1 +ORDER BY max; +max i +3 # + +EXPLAIN +SELECT MAX(pk) as max, i +FROM t1 +ORDER BY max; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using temporary + +# Only 11 is correct for collumn i in this result +SELECT MAX(pk) as max, i +FROM t1 +WHERE pk<2 +ORDER BY max; +max i +1 11 +# +# Cleanup +# +DROP TABLE t1; +End of 5.1 tests diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index 88a822a2fa6..ffdacc43735 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -608,4 +608,146 @@ SELECT SUM( DISTINCT e ) FROM t1 GROUP BY b,c,d HAVING (b,c,d) IN ((AVG( 1 ), 1 + c, 1 + d), (AVG( 1 ), 2 + c, 2 + d)); SUM( DISTINCT e ) DROP TABLE t1; +# +# Bug #44139: Table scan when NULL appears in IN clause +# +CREATE TABLE t1 ( +c_int INT NOT NULL, +c_decimal DECIMAL(5,2) NOT NULL, +c_float FLOAT(5, 2) NOT NULL, +c_bit BIT(10) NOT NULL, +c_date DATE NOT NULL, +c_datetime DATETIME NOT NULL, +c_timestamp TIMESTAMP NOT NULL, +c_time TIME NOT NULL, +c_year YEAR NOT NULL, +c_char CHAR(10) NOT NULL, +INDEX(c_int), INDEX(c_decimal), INDEX(c_float), INDEX(c_bit), INDEX(c_date), +INDEX(c_datetime), INDEX(c_timestamp), INDEX(c_time), INDEX(c_year), +INDEX(c_char)); +INSERT INTO t1 (c_int) VALUES (1), (2), (3), (4), (5); +INSERT INTO t1 (c_int) SELECT 0 FROM t1; +INSERT INTO t1 (c_int) SELECT 0 FROM t1; +EXPLAIN SELECT * FROM t1 WHERE c_int IN (1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_int c_int 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_int IN (NULL, 1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_int c_int 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_int IN (1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_int c_int 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_int IN (1, NULL, 2, NULL, 3, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_int c_int 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_int IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_int IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_decimal c_decimal 3 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (NULL, 1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_decimal c_decimal 3 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_float IN (1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_float c_float 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_float IN (NULL, 1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_float c_float 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_float IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_float IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_bit c_bit 2 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (NULL, 1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_bit c_bit 2 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_date +IN ('2009-09-01', '2009-09-02', '2009-09-03'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_date c_date 3 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_date +IN (NULL, '2009-09-01', '2009-09-02', '2009-09-03'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_date c_date 3 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_date IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_date IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_datetime +IN ('2009-09-01 00:00:01', '2009-09-02 00:00:01', '2009-09-03 00:00:01'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_datetime c_datetime 8 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_datetime +IN (NULL, '2009-09-01 00:00:01', '2009-09-02 00:00:01', '2009-09-03 00:00:01'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_datetime c_datetime 8 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_datetime IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_datetime IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_timestamp +IN ('2009-09-01 00:00:01', '2009-09-01 00:00:02', '2009-09-01 00:00:03'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_timestamp c_timestamp 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_timestamp +IN (NULL, '2009-09-01 00:00:01', '2009-09-01 00:00:02', '2009-09-01 00:00:03'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_timestamp c_timestamp 4 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_timestamp IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_timestamp IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_year IN (1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_year c_year 1 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_year IN (NULL, 1, 2, 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_year c_year 1 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_year IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_year IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_char IN ('1', '2', '3'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_char c_char 10 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL, '1', '2', '3'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range c_char c_char 10 NULL 3 Using where +EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL, NULL); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +DROP TABLE t1; +# End of 5.1 tests diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index a0c3935fde0..2a2fe50ad0f 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -2534,6 +2534,15 @@ SELECT LOAD_FILE(a) FROM t1; LOAD_FILE(a) NULL DROP TABLE t1; +CREATE TABLE t1 (f2 VARCHAR(20)); +CREATE TABLE t2 (f2 VARCHAR(20)); +INSERT INTO t1 VALUES ('MIN'),('MAX'); +INSERT INTO t2 VALUES ('LOAD'); +SELECT CONCAT_WS('_', (SELECT t2.f2 FROM t2), t1.f2) AS concat_name FROM t1; +concat_name +LOAD_MIN +LOAD_MAX +DROP TABLE t1, t2; End of 5.0 tests drop table if exists t1; create table t1(f1 tinyint default null)engine=myisam; diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index 77c340bbdec..4fa2f63598c 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -1037,4 +1037,43 @@ MBRINTERSECTS(b, GEOMFROMTEXT('LINESTRING(1 1,1102219 2)') ); COUNT(*) 2 DROP TABLE t1; +# +# Bug #48258: Assertion failed when using a spatial index +# +CREATE TABLE t1(a LINESTRING NOT NULL, SPATIAL KEY(a)); +INSERT INTO t1 VALUES +(GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')), +(GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')); +EXPLAIN SELECT 1 FROM t1 WHERE a = GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 2 Using where +SELECT 1 FROM t1 WHERE a = GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +1 +1 +1 +EXPLAIN SELECT 1 FROM t1 WHERE a < GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 2 Using where +SELECT 1 FROM t1 WHERE a < GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +1 +EXPLAIN SELECT 1 FROM t1 WHERE a <= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 2 Using where +SELECT 1 FROM t1 WHERE a <= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +1 +1 +1 +EXPLAIN SELECT 1 FROM t1 WHERE a > GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 2 Using where +SELECT 1 FROM t1 WHERE a > GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +1 +EXPLAIN SELECT 1 FROM t1 WHERE a >= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL a NULL NULL NULL 2 Using where +SELECT 1 FROM t1 WHERE a >= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +1 +1 +1 +DROP TABLE t1; End of 5.0 tests. diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index a3708d06a1c..b40ff6be160 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -972,6 +972,18 @@ select min(`col002`) from t1 union select `col002` from t1; min(`col002`) NULL drop table t1; +# +# Bug #47780: crash when comparing GIS items from subquery +# +CREATE TABLE t1(a INT, b MULTIPOLYGON); +INSERT INTO t1 VALUES +(0, +GEOMFROMTEXT( +'multipolygon(((1 2,3 4,5 6,7 8,9 8),(7 6,5 4,3 2,1 2,3 4)))')); +# must not crash +SELECT 1 FROM t1 WHERE a <> (SELECT GEOMETRYCOLLECTIONFROMWKB(b) FROM t1); +1 +DROP TABLE t1; End of 5.0 tests create table t1 (f1 tinyint(1), f2 char(1), f3 varchar(1), f4 geometry, f5 datetime); create view v1 as select * from t1; diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index a677d71b266..92beccd2a9e 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1007,8 +1007,8 @@ DROP TABLE mysqltest1.t2; SHOW GRANTS; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' -GRANT SELECT, INSERT, CREATE, DROP, ALTER ON `mysqltest1`.`t2` TO 'mysqltest_1'@'localhost' GRANT SELECT, INSERT, CREATE, DROP, ALTER ON `mysqltest1`.`t1` TO 'mysqltest_1'@'localhost' +GRANT SELECT, INSERT, CREATE, DROP, ALTER ON `mysqltest1`.`t2` TO 'mysqltest_1'@'localhost' RENAME TABLE t1 TO t2; RENAME TABLE t2 TO t1; ALTER TABLE t1 RENAME TO t2; @@ -1018,8 +1018,8 @@ REVOKE DROP, INSERT ON mysqltest1.t2 FROM mysqltest_1@localhost; SHOW GRANTS; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' -GRANT SELECT, CREATE, ALTER ON `mysqltest1`.`t2` TO 'mysqltest_1'@'localhost' GRANT SELECT, CREATE, ALTER ON `mysqltest1`.`t1` TO 'mysqltest_1'@'localhost' +GRANT SELECT, CREATE, ALTER ON `mysqltest1`.`t2` TO 'mysqltest_1'@'localhost' RENAME TABLE t1 TO t2; ERROR 42000: DROP command denied to user 'mysqltest_1'@'localhost' for table 't1' ALTER TABLE t1 RENAME TO t2; diff --git a/mysql-test/r/grant3.result b/mysql-test/r/grant3.result index f38848111ad..59c64ee84ae 100644 --- a/mysql-test/r/grant3.result +++ b/mysql-test/r/grant3.result @@ -154,4 +154,42 @@ SELECT * FROM mysqltest_1.t1; a DROP USER 'mysqltest1'@'%'; DROP DATABASE mysqltest_1; +# +# Bug#41597 - After rename of user, there are additional grants +# when grants are reapplied. +# +CREATE DATABASE temp; +CREATE TABLE temp.t1(a INT, b VARCHAR(10)); +INSERT INTO temp.t1 VALUES(1, 'name1'); +INSERT INTO temp.t1 VALUES(2, 'name2'); +INSERT INTO temp.t1 VALUES(3, 'name3'); +CREATE USER 'user1'@'%'; +RENAME USER 'user1'@'%' TO 'user2'@'%'; +# Show privileges after rename and BEFORE grant +SHOW GRANTS FOR 'user2'@'%'; +Grants for user2@% +GRANT USAGE ON *.* TO 'user2'@'%' +GRANT SELECT (a), INSERT (b) ON `temp`.`t1` TO 'user2'@'%'; +# Show privileges after rename and grant +SHOW GRANTS FOR 'user2'@'%'; +Grants for user2@% +GRANT USAGE ON *.* TO 'user2'@'%' +GRANT SELECT (a), INSERT (b) ON `temp`.`t1` TO 'user2'@'%' +# Connect as the renamed user +SHOW GRANTS; +Grants for user2@% +GRANT USAGE ON *.* TO 'user2'@'%' +GRANT SELECT (a), INSERT (b) ON `temp`.`t1` TO 'user2'@'%' +SELECT a FROM temp.t1; +a +1 +2 +3 +# Check for additional privileges by accessing a +# non privileged column. We shouldn't be able to +# access this column. +SELECT b FROM temp.t1; +ERROR 42000: SELECT command denied to user 'user2'@'localhost' for column 'b' in table 't1' +DROP USER 'user2'@'%'; +DROP DATABASE temp; End of 5.0 tests diff --git a/mysql-test/r/grant_lowercase_fs.result b/mysql-test/r/grant_lowercase_fs.result new file mode 100644 index 00000000000..5a3087ed5cd --- /dev/null +++ b/mysql-test/r/grant_lowercase_fs.result @@ -0,0 +1,16 @@ +create database db1; +GRANT CREATE ON db1.* to user_1@localhost; +GRANT SELECT ON db1.* to USER_1@localhost; +CREATE TABLE t1(f1 int); +SELECT * FROM t1; +ERROR 42000: SELECT command denied to user 'user_1'@'localhost' for table 't1' +SELECT * FROM t1; +f1 +CREATE TABLE t2(f1 int); +ERROR 42000: CREATE command denied to user 'USER_1'@'localhost' for table 't2' +REVOKE ALL PRIVILEGES, GRANT OPTION FROM user_1@localhost; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM USER_1@localhost; +DROP USER user_1@localhost; +DROP USER USER_1@localhost; +DROP DATABASE db1; +use test; diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index ac9a53ca238..620f5dc19ec 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -876,10 +876,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by explain select a1,a2,b, max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t1 where (c > 'b111') and (c <= 'g112') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL idx_t1_1 163 NULL 17 Using where; Using index for group-by @@ -924,7 +924,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by explain select a1,a2,b, max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range NULL idx_t2_1 146 NULL # Using where; Using index for group-by +1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t2 where (c > 'b1') or (c <= 'g1') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range NULL idx_t2_1 163 NULL # Using where; Using index for group-by diff --git a/mysql-test/r/have_debug_sync.require b/mysql-test/r/have_debug_sync.require new file mode 100644 index 00000000000..c2090bc5657 --- /dev/null +++ b/mysql-test/r/have_debug_sync.require @@ -0,0 +1,2 @@ +debug_sync +1 diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result index 01c81f639ab..a6f81d7688b 100644 --- a/mysql-test/r/information_schema_db.result +++ b/mysql-test/r/information_schema_db.result @@ -108,7 +108,7 @@ show create view testdb_1.v7; View Create View character_set_client collation_connection v7 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such_user`@`no_such_host` SQL SECURITY DEFINER VIEW `v7` AS select `testdb_1`.`t2`.`f1` AS `f1` from `t2` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'testdb_1.v7' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist show fields from testdb_1.v7; Field Type Null Key Default Extra f1 char(4) YES NULL @@ -138,7 +138,7 @@ show create view testdb_1.v7; View Create View character_set_client collation_connection v7 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such_user`@`no_such_host` SQL SECURITY DEFINER VIEW `v7` AS select `testdb_1`.`t2`.`f1` AS `f1` from `t2` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'testdb_1.v7' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist revoke insert(f1) on v3 from testdb_2@localhost; revoke show view on v5 from testdb_2@localhost; use testdb_1; @@ -156,7 +156,8 @@ ERROR 42000: SELECT command denied to user 'testdb_2'@'localhost' for table 'v7' show create view testdb_1.v7; ERROR 42000: SELECT command denied to user 'testdb_2'@'localhost' for table 'v7' show create view v4; -ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +View Create View character_set_client collation_connection +v4 CREATE ALGORITHM=UNDEFINED DEFINER=`testdb_2`@`localhost` SQL SECURITY DEFINER VIEW `v4` AS select `v3`.`f1` AS `f1`,`v3`.`f2` AS `f2` from `testdb_1`.`v3` latin1 latin1_swedish_ci show fields from v4; Field Type Null Key Default Extra f1 char(4) YES NULL diff --git a/mysql-test/r/innodb-autoinc.result b/mysql-test/r/innodb-autoinc.result index 8174ba52b41..a40a13dbe9f 100644 --- a/mysql-test/r/innodb-autoinc.result +++ b/mysql-test/r/innodb-autoinc.result @@ -197,7 +197,7 @@ c1 c2 5 9 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -230,7 +230,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -269,7 +269,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -282,7 +282,7 @@ SELECT * FROM t1; c1 -1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -315,7 +315,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -330,7 +330,7 @@ SELECT * FROM t1; c1 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -370,7 +370,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -385,7 +385,7 @@ SELECT * FROM t1; c1 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 100 auto_increment_offset 10 @@ -419,7 +419,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -434,7 +434,7 @@ c1 1 9223372036854775794 SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 2 auto_increment_offset 10 @@ -452,7 +452,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -467,7 +467,7 @@ c1 1 18446744073709551603 SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 2 auto_increment_offset 10 @@ -485,7 +485,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -500,7 +500,7 @@ c1 1 18446744073709551603 SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 5 auto_increment_offset 7 @@ -514,7 +514,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -533,7 +533,7 @@ c1 -9223372036854775806 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 3 auto_increment_offset 3 @@ -550,7 +550,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -568,7 +568,7 @@ SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCRE Warnings: Warning 1292 Truncated incorrect auto_increment_increment value: '1152921504606846976' Warning 1292 Truncated incorrect auto_increment_offset value: '1152921504606846976' -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 65535 auto_increment_offset 65535 @@ -581,7 +581,7 @@ c1 DROP TABLE t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 1 auto_increment_offset 1 @@ -867,3 +867,262 @@ INSERT INTO t2 SELECT NULL FROM t1; Got one of the listed errors DROP TABLE t1; DROP TABLE t2; +SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; +CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (null); +INSERT INTO t1 VALUES (null); +ALTER TABLE t1 CHANGE c1 d1 INT NOT NULL AUTO_INCREMENT; +SELECT * FROM t1; +d1 +1 +3 +SELECT * FROM t1; +d1 +1 +3 +INSERT INTO t1 VALUES(null); +Got one of the listed errors +ALTER TABLE t1 AUTO_INCREMENT = 3; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `d1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`d1`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES(null); +SELECT * FROM t1; +d1 +1 +3 +4 +DROP TABLE t1; +SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; +SHOW VARIABLES LIKE "%auto_inc%"; +Variable_name Value +auto_increment_increment 1 +auto_increment_offset 1 +CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-127, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` tinyint(4) NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +-127 innodb +-1 innodb +1 NULL +2 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 TINYINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (-127, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` tinyint(3) unsigned NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +1 NULL +2 innodb +3 innodb +4 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 SMALLINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-32767, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` smallint(6) NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +-32767 innodb +-1 innodb +1 NULL +2 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (-32757, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` smallint(5) unsigned NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +1 NULL +2 innodb +3 innodb +4 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 MEDIUMINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-8388607, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` mediumint(9) NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +-8388607 innodb +-1 innodb +1 NULL +2 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 MEDIUMINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (-8388607, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +1 NULL +2 innodb +3 innodb +4 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-2147483647, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +-2147483647 innodb +-1 innodb +1 NULL +2 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (-2147483647, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(10) unsigned NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +1 NULL +2 innodb +3 innodb +4 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 BIGINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-9223372036854775807, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` bigint(20) NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +-9223372036854775807 innodb +-1 innodb +1 NULL +2 NULL +DROP TABLE t1; +CREATE TABLE t1 (c1 BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (-9223372036854775807, 'innodb'); +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `c2` varchar(10) DEFAULT NULL, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +SELECT * FROM t1; +c1 c2 +1 NULL +2 innodb +3 innodb +4 NULL +DROP TABLE t1; +CREATE TABLE T1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) AUTO_INCREMENT=10 ENGINE=InnoDB; +CREATE INDEX i1 on T1(c2); +SHOW CREATE TABLE T1; +Table Create Table +T1 CREATE TABLE `T1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + `c2` int(11) DEFAULT NULL, + PRIMARY KEY (`c1`), + KEY `i1` (`c2`) +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1 +INSERT INTO T1 (c2) values (0); +SELECT * FROM T1; +c1 c2 +10 0 +DROP TABLE T1; diff --git a/mysql-test/r/innodb_bug44369.result b/mysql-test/r/innodb_bug44369.result new file mode 100644 index 00000000000..9cf79aeffab --- /dev/null +++ b/mysql-test/r/innodb_bug44369.result @@ -0,0 +1,14 @@ +create table bug44369 (DB_ROW_ID int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +create table bug44369 (db_row_id int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +show warnings; +Level Code Message +Warning 1005 Error creating table 'test/bug44369' with column name 'db_row_id'. 'db_row_id' is a reserved name. Please try to re-create the table with a different column name. +Error 1005 Can't create table 'test.bug44369' (errno: -1) +create table bug44369 (db_TRX_Id int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +show warnings; +Level Code Message +Warning 1005 Error creating table 'test/bug44369' with column name 'db_TRX_Id'. 'db_TRX_Id' is a reserved name. Please try to re-create the table with a different column name. +Error 1005 Can't create table 'test.bug44369' (errno: -1) diff --git a/mysql-test/r/innodb_bug46000.result b/mysql-test/r/innodb_bug46000.result new file mode 100644 index 00000000000..b27b3d7443b --- /dev/null +++ b/mysql-test/r/innodb_bug46000.result @@ -0,0 +1,18 @@ +create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; +ERROR 42000: Incorrect index name 'GEN_CLUST_INDEX' +create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; +ERROR 42000: Incorrect index name 'GEN_CLUST_INDEX' +show warnings; +Level Code Message +Warning 1280 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. +Error 1280 Incorrect index name 'GEN_CLUST_INDEX' +Error 1005 Can't create table 'test.bug46000' (errno: -1) +create table bug46000(id int) engine=innodb; +create index GEN_CLUST_INDEX on bug46000(id); +ERROR 42000: Incorrect index name 'GEN_CLUST_INDEX' +show warnings; +Level Code Message +Warning 1280 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. +Error 1280 Incorrect index name 'GEN_CLUST_INDEX' +create index idx on bug46000(id); +drop table bug46000; diff --git a/mysql-test/r/innodb_bug47777.result b/mysql-test/r/innodb_bug47777.result new file mode 100644 index 00000000000..fbba47edcfc --- /dev/null +++ b/mysql-test/r/innodb_bug47777.result @@ -0,0 +1,13 @@ +create table bug47777(c2 linestring not null, primary key (c2(1))) engine=innodb; +insert into bug47777 values (geomfromtext('linestring(1 2,3 4,5 6,7 8,9 10)')); +select count(*) from bug47777 where c2 =geomfromtext('linestring(1 2,3 4,5 6,7 8,9 10)'); +count(*) +1 +update bug47777 set c2=GeomFromText('POINT(1 1)'); +select count(*) from bug47777 where c2 =geomfromtext('linestring(1 2,3 4,5 6,7 8,9 10)'); +count(*) +0 +select count(*) from bug47777 where c2 = GeomFromText('POINT(1 1)'); +count(*) +1 +drop table bug47777; diff --git a/mysql-test/r/innodb_lock_wait_timeout_1.result b/mysql-test/r/innodb_lock_wait_timeout_1.result new file mode 100644 index 00000000000..a635b0d527a --- /dev/null +++ b/mysql-test/r/innodb_lock_wait_timeout_1.result @@ -0,0 +1,357 @@ +# +# Bug #40113: Embedded SELECT inside UPDATE or DELETE can timeout +# without error +# +CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b)) ENGINE=InnoDB; +INSERT INTO t1 (a,b) VALUES (1070109,99); +CREATE TABLE t2 (b int, a int, PRIMARY KEY (b)) ENGINE=InnoDB; +INSERT INTO t2 (b,a) VALUES (7,1070109); +SELECT * FROM t1; +a b +1070109 99 +BEGIN; +SELECT b FROM t2 WHERE b=7 FOR UPDATE; +b +7 +BEGIN; +SELECT b FROM t2 WHERE b=7 FOR UPDATE; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +INSERT INTO t1 (a) VALUES ((SELECT a FROM t2 WHERE b=7)); +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +UPDATE t1 SET a='7000000' WHERE a=(SELECT a FROM t2 WHERE b=7); +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +DELETE FROM t1 WHERE a=(SELECT a FROM t2 WHERE b=7); +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +SELECT * FROM t1; +a b +1070109 99 +DROP TABLE t2, t1; +# End of 5.0 tests +# +# Bug#46539 Various crashes on INSERT IGNORE SELECT + SELECT +# FOR UPDATE +# +drop table if exists t1; +create table t1 (a int primary key auto_increment, +b int, index(b)) engine=innodb; +insert into t1 (b) values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10); +set autocommit=0; +begin; +select * from t1 where b=5 for update; +a b +5 5 +insert ignore into t1 (b) select a as b from t1; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +# Cleanup +# +commit; +set autocommit=default; +drop table t1; +# +# Bug#41756 Strange error messages about locks from InnoDB +# +drop table if exists t1; +# In the default transaction isolation mode, and/or with +# innodb_locks_unsafe_for_binlog=OFF, handler::unlock_row() +# in InnoDB does nothing. +# Thus in order to reproduce the condition that led to the +# warning, one needs to relax isolation by either +# setting a weaker tx_isolation value, or by turning on +# the unsafe replication switch. +# For testing purposes, choose to tweak the isolation level, +# since it's settable at runtime, unlike +# innodb_locks_unsafe_for_binlog, which is +# only a command-line switch. +# +set @@session.tx_isolation="read-committed"; +# Prepare data. We need a table with a unique index, +# for join_read_key to be used. The other column +# allows to control what passes WHERE clause filter. +create table t1 (a int primary key, b int) engine=innodb; +# Let's make sure t1 has sufficient amount of rows +# to exclude JT_ALL access method when reading it, +# i.e. make sure that JT_EQ_REF(a) is always preferred. +insert into t1 values (1,1), (2,null), (3,1), (4,1), +(5,1), (6,1), (7,1), (8,1), (9,1), (10,1), +(11,1), (12,1), (13,1), (14,1), (15,1), +(16,1), (17,1), (18,1), (19,1), (20,1); +# +# Demonstrate that for the SELECT statement +# used later in the test JT_EQ_REF access method is used. +# +explain +select 1 from t1 natural join (select 2 as a, 1 as b union all +select 2 as a, 2 as b) as t2 for update; +id 1 +select_type PRIMARY +table <derived2> +type ALL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows 2 +Extra +id 1 +select_type PRIMARY +table t1 +type eq_ref +possible_keys PRIMARY +key PRIMARY +key_len 4 +ref t2.a +rows 1 +Extra Using where +id 2 +select_type DERIVED +table NULL +type NULL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows NULL +Extra No tables used +id 3 +select_type UNION +table NULL +type NULL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows NULL +Extra No tables used +id NULL +select_type UNION RESULT +table <union2,3> +type ALL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows NULL +Extra +# +# Demonstrate that the reported SELECT statement +# no longer produces warnings. +# +select 1 from t1 natural join (select 2 as a, 1 as b union all +select 2 as a, 2 as b) as t2 for update; +1 +commit; +# +# Demonstrate that due to lack of inter-sweep "reset" function, +# we keep some non-matching records locked, even though we know +# we could unlock them. +# To do that, show that if there is only one distinct value +# for a in t2 (a=2), we will keep record (2,null) in t1 locked. +# But if we add another value for "a" to t2, say 6, +# join_read_key cache will be pruned at least once, +# and thus record (2, null) in t1 will get unlocked. +# +begin; +select 1 from t1 natural join (select 2 as a, 1 as b union all +select 2 as a, 2 as b) as t2 for update; +1 +# +# Switching to connection con1 +# We should be able to delete all records from t1 except (2, null), +# since they were not locked. +begin; +# Delete in series of 3 records so that full scan +# is not used and we're not blocked on record (2,null) +delete from t1 where a in (1,3,4); +delete from t1 where a in (5,6,7); +delete from t1 where a in (8,9,10); +delete from t1 where a in (11,12,13); +delete from t1 where a in (14,15,16); +delete from t1 where a in (17,18); +delete from t1 where a in (19,20); +# +# Record (2, null) is locked. This is actually unnecessary, +# because the previous select returned no rows. +# Just demonstrate the effect. +# +delete from t1; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +rollback; +# +# Switching to connection default +# +# Show that the original contents of t1 is intact: +select * from t1; +a b +1 1 +2 NULL +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +16 1 +17 1 +18 1 +19 1 +20 1 +commit; +# +# Have a one more record in t2 to show that +# if join_read_key cache is purned, the current +# row under the cursor is unlocked (provided, this row didn't +# match the partial WHERE clause, of course). +# Sic: the result of this test dependent on the order of retrieval +# of records --echo # from the derived table, if ! +# We use DELETE to disable the JOIN CACHE. This DELETE modifies no +# records. It also should leave no InnoDB row locks. +# +begin; +delete t1.* from t1 natural join (select 2 as a, 2 as b union all +select 0 as a, 0 as b) as t2; +# Demonstrate that nothing was deleted form t1 +select * from t1; +a b +1 1 +2 NULL +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +16 1 +17 1 +18 1 +19 1 +20 1 +# +# Switching to connection con1 +begin; +# Since there is another distinct record in the derived table +# the previous matching record in t1 -- (2,null) -- was unlocked. +delete from t1; +# We will need the contents of the table again. +rollback; +select * from t1; +a b +1 1 +2 NULL +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +16 1 +17 1 +18 1 +19 1 +20 1 +commit; +# +# Switching to connection default +rollback; +begin; +# +# Before this patch, we could wrongly unlock a record +# that was cached and later used in a join. Demonstrate that +# this is no longer the case. +# Sic: this test is also order-dependent (i.e. the +# the bug would show up only if the first record in the union +# is retreived and processed first. +# +# Verify that JT_EQ_REF is used. +explain +select 1 from t1 natural join (select 3 as a, 2 as b union all +select 3 as a, 1 as b) as t2 for update; +id 1 +select_type PRIMARY +table <derived2> +type ALL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows 2 +Extra +id 1 +select_type PRIMARY +table t1 +type eq_ref +possible_keys PRIMARY +key PRIMARY +key_len 4 +ref t2.a +rows 1 +Extra Using where +id 2 +select_type DERIVED +table NULL +type NULL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows NULL +Extra No tables used +id 3 +select_type UNION +table NULL +type NULL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows NULL +Extra No tables used +id NULL +select_type UNION RESULT +table <union2,3> +type ALL +possible_keys NULL +key NULL +key_len NULL +ref NULL +rows NULL +Extra +# Lock the record. +select 1 from t1 natural join (select 3 as a, 2 as b union all +select 3 as a, 1 as b) as t2 for update; +1 +1 +# Switching to connection con1 +# +# We should not be able to delete record (3,1) from t1, +# (previously it was possible). +# +delete from t1 where a=3; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +# Switching to connection default +commit; +set @@session.tx_isolation=default; +drop table t1; +# +# End of 5.1 tests +# diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 3ff5f04b6c6..c882d2af1ed 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -385,9 +385,10 @@ name dept rs5 cs10 rs5 cs9 DELETE FROM t1; +# Masking (#) number in "rows" column of the following EXPLAIN output, as it may vary (bug#47746). EXPLAIN SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range name name 44 NULL 2 Using where; Using index for group-by +1 SIMPLE t1 range name name 44 NULL # Using where; Using index for group-by SELECT DISTINCT t1.name, t1.dept FROM t1 WHERE t1.name='rs5'; name dept DROP TABLE t1; @@ -2208,4 +2209,46 @@ EXPLAIN SELECT * FROM t1 FORCE INDEX(PRIMARY) WHERE b=1 AND c=1 ORDER BY a; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 128 Using where DROP TABLE t1; +# +# Bug #47963: Wrong results when index is used +# +CREATE TABLE t1( +a VARCHAR(5) NOT NULL, +b VARCHAR(5) NOT NULL, +c DATETIME NOT NULL, +KEY (c) +) ENGINE=InnoDB; +INSERT INTO t1 VALUES('TEST', 'TEST', '2009-10-09 00:00:00'); +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00' AND c <= '2009-10-09 00:00:00'; +a b c +TEST TEST 2009-10-09 00:00:00 +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00.0' AND c <= '2009-10-09 00:00:00.0'; +a b c +TEST TEST 2009-10-09 00:00:00 +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00.0' AND c <= '2009-10-09 00:00:00'; +a b c +TEST TEST 2009-10-09 00:00:00 +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00' AND c <= '2009-10-09 00:00:00.0'; +a b c +TEST TEST 2009-10-09 00:00:00 +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00.000' AND c <= '2009-10-09 00:00:00.000'; +a b c +TEST TEST 2009-10-09 00:00:00 +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00.00' AND c <= '2009-10-09 00:00:00.001'; +a b c +TEST TEST 2009-10-09 00:00:00 +SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00'; +a b c +EXPLAIN SELECT * FROM t1 WHERE a = 'TEST' AND +c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 94c58497101..cf3c0b0731e 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -833,3 +833,17 @@ Table Op Msg_type Msg_text test.t2 check status OK drop table t1,t2; End of 5.0 tests +################################################################## +# +# Bug #46075: Assertion failed: 0, file .\protocol.cc, line 416 +# +CREATE TABLE t1(a INT); +SET max_heap_table_size = 16384; +SET @old_myisam_data_pointer_size = @@myisam_data_pointer_size; +SET GLOBAL myisam_data_pointer_size = 2; +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); +call mtr.add_suppression("mysqld: The table '.*#sql.*' is full"); +INSERT IGNORE INTO t1 SELECT t1.a FROM t1,t1 t2,t1 t3,t1 t4,t1 t5,t1 t6,t1 t7; +SET GLOBAL myisam_data_pointer_size = @old_myisam_data_pointer_size; +DROP TABLE t1; +End of 5.1 tests diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result index 736ecf1d90e..baabf48cb2f 100644 --- a/mysql-test/r/join.result +++ b/mysql-test/r/join.result @@ -1063,4 +1063,68 @@ a b c d 127 NULL 127 NULL 128 NULL 128 NULL DROP TABLE IF EXISTS t1,t2; +# +# Bug #42116: Mysql crash on specific query +# +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +CREATE TABLE t3 (a INT, INDEX (a)); +CREATE TABLE t4 (a INT); +CREATE TABLE t5 (a INT); +CREATE TABLE t6 (a INT); +INSERT INTO t1 VALUES (1), (1), (1); +INSERT INTO t2 VALUES +(2), (2), (2), (2), (2), (2), (2), (2), (2), (2); +INSERT INTO t3 VALUES +(3), (3), (3), (3), (3), (3), (3), (3), (3), (3); +EXPLAIN +SELECT * +FROM +t1 JOIN t2 ON t1.a = t2.a +LEFT JOIN +( +( +t3 LEFT JOIN t4 ON t3.a = t4.a +) +LEFT JOIN +( +t5 LEFT JOIN t6 ON t5.a = t6.a +) +ON t4.a = t5.a +) +ON t1.a = t3.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 +1 SIMPLE t3 ref a a 5 test.t1.a 2 Using index +1 SIMPLE t4 ALL NULL NULL NULL NULL 0 +1 SIMPLE t5 ALL NULL NULL NULL NULL 0 +1 SIMPLE t6 ALL NULL NULL NULL NULL 0 +1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using where; Using join buffer +SELECT * +FROM +t1 JOIN t2 ON t1.a = t2.a +LEFT JOIN +( +( +t3 LEFT JOIN t4 ON t3.a = t4.a +) +LEFT JOIN +( +t5 LEFT JOIN t6 ON t5.a = t6.a +) +ON t4.a = t5.a +) +ON t1.a = t3.a; +a a a a a a +DROP TABLE t1,t2,t3,t4,t5,t6; End of 5.0 tests. +CREATE TABLE t1 (f1 int); +CREATE TABLE t2 (f1 int); +INSERT INTO t2 VALUES (1); +CREATE VIEW v1 AS SELECT * FROM t2; +PREPARE stmt FROM 'UPDATE t2 AS A NATURAL JOIN v1 B SET B.f1 = 1'; +EXECUTE stmt; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +DROP VIEW v1; +DROP TABLE t1, t2; diff --git a/mysql-test/r/locale.result b/mysql-test/r/locale.result new file mode 100644 index 00000000000..89883b070d2 --- /dev/null +++ b/mysql-test/r/locale.result @@ -0,0 +1,29 @@ +DROP TABLE IF EXISTS t1; +Start of 5.4 tests +# +# Bug#43207 wrong LC_TIME names for romanian locale +# +SET NAMES utf8; +SET lc_time_names=ro_RO; +SELECT DATE_FORMAT('2001-01-01', '%w %a %W'); +DATE_FORMAT('2001-01-01', '%w %a %W') +1 Lu Luni +SELECT DATE_FORMAT('2001-01-02', '%w %a %W'); +DATE_FORMAT('2001-01-02', '%w %a %W') +2 Ma MarÅ£i +SELECT DATE_FORMAT('2001-01-03', '%w %a %W'); +DATE_FORMAT('2001-01-03', '%w %a %W') +3 Mi Miercuri +SELECT DATE_FORMAT('2001-01-04', '%w %a %W'); +DATE_FORMAT('2001-01-04', '%w %a %W') +4 Jo Joi +SELECT DATE_FORMAT('2001-01-05', '%w %a %W'); +DATE_FORMAT('2001-01-05', '%w %a %W') +5 Vi Vineri +SELECT DATE_FORMAT('2001-01-06', '%w %a %W'); +DATE_FORMAT('2001-01-06', '%w %a %W') +6 Sâ Sâmbătă +SELECT DATE_FORMAT('2001-01-07', '%w %a %W'); +DATE_FORMAT('2001-01-07', '%w %a %W') +0 Du Duminică +End of 5.4 tests diff --git a/mysql-test/r/lowercase_fs_off.result b/mysql-test/r/lowercase_fs_off.result index ecb21261987..4a59801692d 100644 --- a/mysql-test/r/lowercase_fs_off.result +++ b/mysql-test/r/lowercase_fs_off.result @@ -10,3 +10,48 @@ create database D1; ERROR 42000: Access denied for user 'sample'@'localhost' to database 'D1' drop user 'sample'@'localhost'; drop database if exists d1; +CREATE DATABASE d1; +USE d1; +CREATE TABLE T1(f1 INT); +CREATE TABLE t1(f1 INT); +GRANT SELECT ON T1 to user_1@localhost; +select * from t1; +ERROR 42000: SELECT command denied to user 'user_1'@'localhost' for table 't1' +select * from T1; +f1 +GRANT SELECT ON t1 to user_1@localhost; +select * from information_schema.table_privileges; +GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE +'user_1'@'localhost' NULL d1 T1 SELECT NO +'user_1'@'localhost' NULL d1 t1 SELECT NO +REVOKE ALL PRIVILEGES, GRANT OPTION FROM user_1@localhost; +DROP USER user_1@localhost; +DROP DATABASE d1; +USE test; +CREATE DATABASE db1; +USE db1; +CREATE PROCEDURE p1() BEGIN END; +CREATE FUNCTION f1(i INT) RETURNS INT RETURN i+1; +GRANT USAGE ON db1.* to user_1@localhost; +GRANT EXECUTE ON PROCEDURE db1.P1 to user_1@localhost; +GRANT EXECUTE ON FUNCTION db1.f1 to user_1@localhost; +GRANT UPDATE ON db1.* to USER_1@localhost; +call p1(); +call P1(); +select f1(1); +f1(1) +2 +call p1(); +ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.p1' +call P1(); +ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.p1' +select f1(1); +ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.f1' +REVOKE ALL PRIVILEGES, GRANT OPTION FROM user_1@localhost; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM USER_1@localhost; +DROP FUNCTION f1; +DROP PROCEDURE p1; +DROP USER user_1@localhost; +DROP USER USER_1@localhost; +DROP DATABASE db1; +use test; diff --git a/mysql-test/r/lowercase_mixed_tmpdir_innodb.result b/mysql-test/r/lowercase_mixed_tmpdir_innodb.result new file mode 100755 index 00000000000..a478b49cfda --- /dev/null +++ b/mysql-test/r/lowercase_mixed_tmpdir_innodb.result @@ -0,0 +1,6 @@ +drop table if exists t1; +create table t1 (id int) engine=InnoDB; +insert into t1 values (1); +create temporary table t2 engine=InnoDB select * from t1; +drop temporary table t2; +drop table t1; diff --git a/mysql-test/r/lowercase_table3.result b/mysql-test/r/lowercase_table3.result index 1ef7d04bb1d..22e80aaeb26 100644 --- a/mysql-test/r/lowercase_table3.result +++ b/mysql-test/r/lowercase_table3.result @@ -1,4 +1,4 @@ -call mtr.add_suppression("Cannot find or open table test/BUG29839 from .*"); +call mtr.add_suppression("Cannot find or open table test/BUG29839 from"); DROP TABLE IF EXISTS t1,T1; CREATE TABLE t1 (a INT); SELECT * FROM T1; diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 0a02c25c322..ed4505b6073 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -2283,4 +2283,50 @@ h+0 d + 0 e g + 0 1 1 3 0 1 1 4 0 DROP TABLE t1; +# +# Test of BUG#35570 CHECKSUM TABLE unreliable if LINESTRING field +# (same content / differen checksum) +# +CREATE TABLE t1 (line LINESTRING NOT NULL) engine=myisam; +INSERT INTO t1 VALUES (GeomFromText("POINT(0 0)")); +checksum table t1; +Table Checksum +test.t1 326284887 +CREATE TABLE t2 (line LINESTRING NOT NULL) engine=myisam; +INSERT INTO t2 VALUES (GeomFromText("POINT(0 0)")); +checksum table t2; +Table Checksum +test.t2 326284887 +CREATE TABLE t3 select * from t1; +checksum table t3; +Table Checksum +test.t3 326284887 +drop table t1,t2,t3; +CREATE TABLE t1(a INT, b CHAR(10), KEY(a), KEY(b)); +INSERT INTO t1 VALUES(1,'0'),(2,'0'),(3,'0'),(4,'0'),(5,'0'), +(6,'0'),(7,'0'); +INSERT INTO t1 SELECT a+10,b FROM t1; +INSERT INTO t1 SELECT a+20,b FROM t1; +INSERT INTO t1 SELECT a+40,b FROM t1; +INSERT INTO t1 SELECT a+80,b FROM t1; +INSERT INTO t1 SELECT a+160,b FROM t1; +INSERT INTO t1 SELECT a+320,b FROM t1; +INSERT INTO t1 SELECT a+640,b FROM t1; +INSERT INTO t1 SELECT a+1280,b FROM t1; +INSERT INTO t1 SELECT a+2560,b FROM t1; +INSERT INTO t1 SELECT a+5120,b FROM t1; +SET myisam_sort_buffer_size=4; +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair error myisam_sort_buffer_size is too small +test.t1 repair warning Number of rows changed from 0 to 7168 +test.t1 repair status OK +SET myisam_repair_threads=2; +REPAIR TABLE t1; +SET myisam_repair_threads=@@global.myisam_repair_threads; +SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/r/myisam_crash_before_flush_keys.result b/mysql-test/r/myisam_crash_before_flush_keys.result index 372f2e41590..d3545ea47d0 100644 --- a/mysql-test/r/myisam_crash_before_flush_keys.result +++ b/mysql-test/r/myisam_crash_before_flush_keys.result @@ -15,31 +15,13 @@ SET SESSION debug="d,crash_before_flush_keys"; # Run the crashing query FLUSH TABLE t1; ERROR HY000: Lost connection to MySQL server during query -# Run MYISAMCHK tool to check the table t1 and repair -myisamchk: MyISAM file MYSQLD_DATADIR/test/t1 -myisamchk: warning: 1 client is using or hasn't closed the table properly -myisamchk: error: Size of indexfile is: 1024 Should be: 3072 -MYISAMCHK: Unknown error 126 -myisamchk: error: Can't read indexpage from filepos: 1024 -MyISAM-table 'MYSQLD_DATADIR/test/t1' is corrupted -Fix it using switch "-r" or "-o" # Write file to make mysql-test-run.pl start the server # Turn on reconnect # Call script that will poll the server waiting for # it to be back online again -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL DEFAULT '0', - `b` int(11) NOT NULL DEFAULT '0', - PRIMARY KEY (`a`,`b`), - KEY `b` (`b`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 DELAY_KEY_WRITE=1 -SELECT * FROM t1 FORCE INDEX (PRIMARY); -a b -1 2 -2 3 -3 4 -4 5 -5 6 +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check warning 1 client is using or hasn't closed the table properly +test.t1 check error Size of indexfile is: 1024 Should be: 3072 +test.t1 check error Corrupt DROP TABLE t1; diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result index 295a2f41d40..5f32561798b 100644 --- a/mysql-test/r/mysqlbinlog.result +++ b/mysql-test/r/mysqlbinlog.result @@ -44,16 +44,16 @@ SET TIMESTAMP=1000000000/*!*/; insert into t2 values () /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; DELIMITER ; # End of log file @@ -144,16 +144,16 @@ SET TIMESTAMP=1000000000/*!*/; insert into t2 values () /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (word) /*!*/; DELIMITER ; # End of log file @@ -359,29 +359,29 @@ SET @@session.collation_database=DEFAULT/*!*/; create table t1 (a varchar(64) character set utf8) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.collation_database=7/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.collation_database=DEFAULT/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-#-#' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.collation_database=7/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-a-0' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-a-0' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; SET @@session.collation_database=DEFAULT/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-b-0' INTO table t1 +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-b-0' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; -load data LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-c-0' INTO table t1 character set koi8r +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/tmp/SQL_LOAD_MB-c-0' INTO TABLE `t1` CHARACTER SET koi8r FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) /*!*/; SET TIMESTAMP=1000000000/*!*/; drop table t1 @@ -473,5 +473,94 @@ IS NOT NULL SET @@global.server_id= 1; RESET MASTER; FLUSH LOGS; +RESET MASTER; +FLUSH LOGS; +# +# Test if the 'BEGIN', 'ROLLBACK' and 'COMMIT' are output if the database specified is exist +/*!40019 SET @@session.max_insert_delayed_threads=0*/; +/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; +DELIMITER /*!*/; +ROLLBACK/*!*/; +use test/*!*/; +SET TIMESTAMP=1253783037/*!*/; +SET @@session.pseudo_thread_id=999999999/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1/*!*/; +SET @@session.sql_mode=0/*!*/; +SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; +/*!\C latin1 *//*!*/; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; +SET @@session.lc_time_names=0/*!*/; +SET @@session.collation_database=DEFAULT/*!*/; +create table t1(a int) engine= innodb +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +BEGIN +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +insert into t1 (a) values (1) +/*!*/; +COMMIT/*!*/; +SET TIMESTAMP=1253783037/*!*/; +create table t3(a int) engine= innodb +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +BEGIN +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +insert into t3 (a) values (2) +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +ROLLBACK +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +create table t5(a int) engine= NDB +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +BEGIN +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +insert into t5 (a) values (3) +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +COMMIT +/*!*/; +DELIMITER ; +# End of log file +ROLLBACK /* added by mysqlbinlog */; +/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; +# +# Test if the 'BEGIN', 'ROLLBACK' and 'COMMIT' are output if the database specified is not exist +/*!40019 SET @@session.max_insert_delayed_threads=0*/; +/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; +DELIMITER /*!*/; +ROLLBACK/*!*/; +SET TIMESTAMP=1253783037/*!*/; +SET @@session.pseudo_thread_id=999999999/*!*/; +SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1/*!*/; +SET @@session.sql_mode=0/*!*/; +SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; +/*!\C latin1 *//*!*/; +SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/; +SET @@session.lc_time_names=0/*!*/; +SET @@session.collation_database=DEFAULT/*!*/; +BEGIN +/*!*/; +COMMIT/*!*/; +SET TIMESTAMP=1253783037/*!*/; +BEGIN +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +ROLLBACK +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +BEGIN +/*!*/; +SET TIMESTAMP=1253783037/*!*/; +COMMIT +/*!*/; +DELIMITER ; +# End of log file +ROLLBACK /* added by mysqlbinlog */; +/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/; End of 5.0 tests End of 5.1 tests diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 52a1734ea54..2e3a9489593 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -314,20 +314,10 @@ here is the sourced script 1 = outer loop variable before dec 0 = outer loop variable after dec - -2 = outer loop variable after while +outer=2 ifval=0 +outer=1 ifval=1 here is the sourced script - -2 = outer loop variable before dec - -1 = outer loop variable after dec - -1 = outer loop variable after while -here is the sourced script - -1 = outer loop variable before dec - -0 = outer loop variable after dec +ERROR 42S02: Table 'test.nowhere' doesn't exist In loop here is the sourced script @@ -538,6 +528,10 @@ mysqltest: At line 1: Missing required argument 'filename' to command 'write_fil mysqltest: At line 1: End of file encountered before 'EOF' delimiter was found Content for test_file1 mysqltest: At line 1: File already exist: 'MYSQLTEST_VARDIR/tmp/test_file1.tmp' +These lines should be repeated, +if things work as expected +These lines should be repeated, +if things work as expected Some data for cat_file command of mysqltest diff --git a/mysql-test/r/not_true.require b/mysql-test/r/not_true.require new file mode 100644 index 00000000000..0032832f3d1 --- /dev/null +++ b/mysql-test/r/not_true.require @@ -0,0 +1,2 @@ +TRUE +NULL diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 4540c9d5218..a7516d97888 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -733,4 +733,24 @@ SELECT 1 FROM t1 GROUP BY (DATE(NULL)) WITH ROLLUP; 1 1 DROP TABLE t1; +# +# Bug #48131: crash group by with rollup, distinct, +# filesort, with temporary tables +# +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY); +INSERT INTO t1 VALUES (1), (2); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (100); +SELECT a, b FROM t1, t2 GROUP BY a, b WITH ROLLUP; +a b +1 100 +1 NULL +2 100 +2 NULL +NULL NULL +SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP; +b +100 +NULL +DROP TABLE t1, t2; End of 5.0 tests diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 306fce1f3c2..0c72f816c21 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -1557,3 +1557,34 @@ a 2001 1991 DROP TABLE t1; +# +# Bug #43029: FORCE INDEX FOR ORDER BY is ignored when join buffering +# is used +# +CREATE TABLE t1 (a INT, b INT, KEY (a)); +INSERT INTO t1 VALUES (0, NULL), (1, NULL), (2, NULL), (3, NULL); +INSERT INTO t1 SELECT a+4, b FROM t1; +INSERT INTO t1 SELECT a+8, b FROM t1; +CREATE TABLE t2 (a INT, b INT); +INSERT INTO t2 VALUES (0,NULL), (1,NULL), (2,NULL), (3,NULL), (4,NULL); +INSERT INTO t2 SELECT a+4, b FROM t2; +# shouldn't have "using filesort" +EXPLAIN +SELECT * FROM t1 FORCE INDEX FOR ORDER BY (a), t2 WHERE t1.a < 2 ORDER BY t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where +1 SIMPLE t2 ALL NULL NULL NULL NULL 10 +# should have "using filesort" +EXPLAIN +SELECT * FROM t1 USE INDEX FOR ORDER BY (a), t2 WHERE t1.a < 2 ORDER BY t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where; Using temporary; Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using join buffer +# should have "using filesort" +EXPLAIN +SELECT * FROM t1 FORCE INDEX FOR JOIN (a), t2 WHERE t1.a < 2 ORDER BY t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 2 Using where; Using temporary; Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using join buffer +DROP TABLE t1, t2; +End of 5.1 tests diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 2d54a66fe11..6611d39628f 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -50,6 +50,21 @@ t1 CREATE TABLE `t1` ( PARTITION p3 VALUES LESS THAN (733969) ENGINE = MyISAM, PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ DROP TABLE t1; +create table t1 (a int, b int, key(a)) +partition by list (a) +( partition p0 values in (1), +partition p1 values in (2)); +insert into t1 values (1,1),(2,1),(2,2),(2,3); +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A NULL NULL NULL YES BTREE +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +show indexes from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 1 NULL NULL YES BTREE +drop table t1; CREATE TABLE t1 (a INT, FOREIGN KEY (a) REFERENCES t0 (a)) ENGINE=MyISAM PARTITION BY HASH (a); diff --git a/mysql-test/r/partition_csv.result b/mysql-test/r/partition_csv.result index 07651f29da4..18e28d4670a 100644 --- a/mysql-test/r/partition_csv.result +++ b/mysql-test/r/partition_csv.result @@ -1,3 +1,4 @@ +call mtr.add_suppression("Failed to write to mysql.general_log"); drop table if exists t1; create table t1 (a int) engine = csv diff --git a/mysql-test/r/partition_innodb.result b/mysql-test/r/partition_innodb.result index ad4d08e89ff..b8cfa25349d 100644 --- a/mysql-test/r/partition_innodb.result +++ b/mysql-test/r/partition_innodb.result @@ -1,4 +1,18 @@ drop table if exists t1; +create table t1 (a int not null, +b datetime not null, +primary key (a,b)) +engine=innodb +partition by range (to_days(b)) +subpartition by hash (a) +subpartitions 2 +( partition p0 values less than (to_days('2009-01-01')), +partition p1 values less than (to_days('2009-02-01')), +partition p2 values less than (to_days('2009-03-01')), +partition p3 values less than maxvalue); +alter table t1 reorganize partition p1,p2 into +( partition p2 values less than (to_days('2009-03-01'))); +drop table t1; CREATE TABLE t1 (id INT PRIMARY KEY, data INT) ENGINE = InnoDB PARTITION BY RANGE(id) ( PARTITION p0 VALUES LESS THAN (5), @@ -256,3 +270,7 @@ SUBPARTITION BY KEY (char_column) SUBPARTITIONS 2 (PARTITION p1 VALUES LESS THAN (5) ENGINE = MyISAM) */ drop table t1; +CREATE TABLE t1 (a INT) ENGINE=InnoDB +PARTITION BY list(a) (PARTITION p1 VALUES IN (1)); +CREATE INDEX i1 ON t1 (a); +DROP TABLE t1; diff --git a/mysql-test/r/partition_innodb_builtin.result b/mysql-test/r/partition_innodb_builtin.result new file mode 100644 index 00000000000..384ce0790a4 --- /dev/null +++ b/mysql-test/r/partition_innodb_builtin.result @@ -0,0 +1,39 @@ +SET NAMES utf8; +CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a)) +ENGINE=InnoDB +PARTITION BY RANGE (a) +SUBPARTITION BY HASH (a) +(PARTITION `p0``\""e` VALUES LESS THAN (100) +(SUBPARTITION `sp0``\""e`, +SUBPARTITION `sp1``\""e`), +PARTITION `p1``\""e` VALUES LESS THAN (MAXVALUE) +(SUBPARTITION `sp2``\""e`, +SUBPARTITION `sp3``\""e`)); +INSERT INTO `t``\""e` VALUES (0), (2), (6), (10), (14), (18), (22); +START TRANSACTION; +# con1 +SET NAMES utf8; +START TRANSACTION; +# default connection +UPDATE `t``\""e` SET a = 16 WHERE a = 0; +# con1 +UPDATE `t``\""e` SET a = 8 WHERE a = 22; +UPDATE `t``\""e` SET a = 12 WHERE a = 0; +# default connection +UPDATE `t``\""e` SET a = 4 WHERE a = 22; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +# First table reported in 'SHOW ENGINE InnoDB STATUS' +SHOW ENGINE InnoDB STATUS; +Type Name Status +InnoDB index `PRIMARY` of table `test`.`t``\""e` /* Partition `p0``\""e`, Subpartition `sp0``\""e` */ +set @old_sql_mode = @@sql_mode; +set sql_mode = 'ANSI_QUOTES'; +SHOW ENGINE InnoDB STATUS; +Type Name Status +InnoDB index `PRIMARY` of table `test`.`t``\""e` /* Partition `p0``\""e`, Subpartition `sp0``\""e` */ +set @@sql_mode = @old_sql_mode; +# con1 +ROLLBACK; +# default connection +DROP TABLE `t``\""e`; +SET NAMES DEFAULT; diff --git a/mysql-test/r/partition_innodb_plugin.result b/mysql-test/r/partition_innodb_plugin.result new file mode 100644 index 00000000000..dd91eee316a --- /dev/null +++ b/mysql-test/r/partition_innodb_plugin.result @@ -0,0 +1,50 @@ +SET NAMES utf8; +CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a)) +ENGINE=InnoDB +PARTITION BY RANGE (a) +SUBPARTITION BY HASH (a) +(PARTITION `p0``\""e` VALUES LESS THAN (100) +(SUBPARTITION `sp0``\""e`, +SUBPARTITION `sp1``\""e`), +PARTITION `p1``\""e` VALUES LESS THAN (MAXVALUE) +(SUBPARTITION `sp2``\""e`, +SUBPARTITION `sp3``\""e`)); +INSERT INTO `t``\""e` VALUES (0), (2), (6), (10), (14), (18), (22); +START TRANSACTION; +# con1 +SET NAMES utf8; +START TRANSACTION; +# default connection +UPDATE `t``\""e` SET a = 16 WHERE a = 0; +# con1 +UPDATE `t``\""e` SET a = 8 WHERE a = 22; +UPDATE `t``\""e` SET a = 12 WHERE a = 0; +# default connection +SELECT lock_table, COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS +GROUP BY lock_table; +lock_table COUNT(*) +`test`.`t``\""e` /* Partition `p0``\""e`, Subpartition `sp0``\""e` */ 2 +set @old_sql_mode = @@sql_mode; +set sql_mode = 'ANSI_QUOTES'; +SELECT lock_table, COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS +GROUP BY lock_table; +lock_table COUNT(*) +"test"."t`\""""e" /* Partition "p0`\""""e", Subpartition "sp0`\""""e" */ 2 +set @@sql_mode = @old_sql_mode; +UPDATE `t``\""e` SET a = 4 WHERE a = 22; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +# First table reported in 'SHOW ENGINE InnoDB STATUS' +SHOW ENGINE InnoDB STATUS; +Type Name Status +InnoDB index `PRIMARY` of table `test`.`t``\""e` /* Partition `p0``\""e`, Subpartition `sp0``\""e` */ +set @old_sql_mode = @@sql_mode; +set sql_mode = 'ANSI_QUOTES'; +SHOW ENGINE InnoDB STATUS; +Type Name Status +InnoDB index `PRIMARY` of table `test`.`t``\""e` /* Partition `p0``\""e`, Subpartition `sp0``\""e` */ +set @@sql_mode = @old_sql_mode; +# con1 +ROLLBACK; +# default connection +DROP TABLE `t``\""e`; +SET NAMES DEFAULT; diff --git a/mysql-test/r/partition_open_files_limit.result b/mysql-test/r/partition_open_files_limit.result new file mode 100644 index 00000000000..1441ba4e78e --- /dev/null +++ b/mysql-test/r/partition_open_files_limit.result @@ -0,0 +1,22 @@ +DROP TABLE IF EXISTS `t1`; +# Bug#46922: crash when adding partitions and open_files_limit is reached +CREATE TABLE t1 (a INT PRIMARY KEY) +ENGINE=MyISAM PARTITION BY KEY () PARTITIONS 1; +INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11); +# if the bug exists, then crash will happen here +ALTER TABLE t1 ADD PARTITION PARTITIONS 511; +ERROR HY000: Out of resources when opening file '<partition file>' (Errcode: 24) +SELECT * FROM t1; +a +1 +10 +11 +2 +3 +4 +5 +6 +7 +8 +9 +DROP TABLE t1; diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index 769d499fc0a..3128c57b2cf 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -1272,10 +1272,9 @@ INSERT INTO t1 VALUES (1, '2009-01-01'), (2, NULL); # test with an invalid date, which lead to item->null_value is set. EXPLAIN PARTITIONS SELECT * FROM t1 WHERE b < CAST('2009-04-99' AS DATETIME); id select_type table partitions type possible_keys key key_len ref rows Extra -1 SIMPLE t1 p20090401 ALL NULL NULL NULL NULL 2 Using where +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables Warnings: Warning 1292 Incorrect datetime value: '2009-04-99' -Warning 1292 Incorrect datetime value: '2009-04-99' DROP TABLE t1; CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT, diff --git a/mysql-test/r/ps_grant.result b/mysql-test/r/ps_grant.result index 8b16123ccea..672db74d9c0 100644 --- a/mysql-test/r/ps_grant.result +++ b/mysql-test/r/ps_grant.result @@ -32,19 +32,19 @@ identified by 'looser' ; show grants for second_user@localhost ; Grants for second_user@localhost GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3' -GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost' GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost' +GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost' drop table mysqltest.t9 ; show grants for second_user@localhost ; Grants for second_user@localhost GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3' -GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost' GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost' +GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost' show grants for second_user@localhost ; Grants for second_user@localhost GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3' -GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost' GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost' +GRANT SELECT ON `mysqltest`.`t1` TO 'second_user'@'localhost' prepare s_t1 from 'select a as my_col from t1' ; execute s_t1 ; my_col diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 1c11932107e..a410f7b2dcf 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -1708,6 +1708,7 @@ Qcache_hits 2 DROP TABLE t1; SET GLOBAL query_cache_size= default; End of 5.0 tests +SET GLOBAL query_cache_size=1024*1024*512; CREATE TABLE t1 (a ENUM('rainbow')); INSERT INTO t1 VALUES (),(),(),(),(); SELECT 1 FROM t1 GROUP BY (SELECT 1 FROM t1 ORDER BY AVG(LAST_INSERT_ID())); @@ -1722,4 +1723,5 @@ SELECT 1 FROM t1 GROUP BY 1 1 DROP TABLE t1; +SET GLOBAL query_cache_size= default; End of 5.1 tests diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index cc5e8d2be96..2306f8b501e 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -1219,3 +1219,388 @@ explain select * from t2 where a=1000 and b<11; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ref a a 5 const 502 Using where drop table t1, t2; +CREATE TABLE t1( a INT, b INT, KEY( a, b ) ); +CREATE TABLE t2( a INT, b INT, KEY( a, b ) ); +CREATE TABLE t3( a INT, b INT, KEY( a, b ) ); +INSERT INTO t1( a, b ) +VALUES (0, 1), (1, 2), (1, 4), (2, 3), (5, 0), (9, 7); +INSERT INTO t2( a, b ) +VALUES ( 1, 1), ( 2, 1), ( 3, 1), ( 4, 1), ( 5, 1), +( 6, 1), ( 7, 1), ( 8, 1), ( 9, 1), (10, 1), +(11, 1), (12, 1), (13, 1), (14, 1), (15, 1), +(16, 1), (17, 1), (18, 1), (19, 1), (20, 1); +INSERT INTO t2 SELECT a, 2 FROM t2 WHERE b = 1; +INSERT INTO t2 SELECT a, 3 FROM t2 WHERE b = 1; +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t3 +VALUES (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), +(6, 0), (7, 0), (8, 0), (9, 0), (10, 0); +INSERT INTO t3 SELECT * FROM t3 WHERE a = 10; +INSERT INTO t3 SELECT * FROM t3 WHERE a = 10; +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 < a AND b = 3 OR +3 <= a; +a b +5 0 +9 7 +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 < a AND b = 3 OR +3 <= a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 3 Using where; Using index +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 <= a AND b = 3 OR +3 <= a; +a b +5 0 +9 7 +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 <= a AND b = 3 OR +3 <= a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 4 Using where; Using index +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +5 <= a AND b = 3 OR +3 <= a; +a b +5 0 +9 7 +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +5 <= a AND b = 3 OR +3 <= a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 3 Using where; Using index +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +3 <= a; +a b +5 0 +9 7 +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +3 <= a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 5 NULL 3 Using where; Using index +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 1 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; +a b +1 1 +2 1 +3 1 +4 1 +5 1 +6 1 +7 1 +8 1 +9 1 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +15 3 +16 1 +16 3 +17 1 +17 3 +18 1 +18 3 +19 1 +19 3 +20 1 +EXPLAIN +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 1 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 10 NULL 50 Using where; Using index +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 2 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; +a b +1 1 +2 1 +3 1 +4 1 +5 1 +5 2 +6 1 +6 2 +7 1 +7 2 +8 1 +8 2 +9 1 +9 2 +10 1 +11 1 +12 1 +13 1 +14 1 +15 1 +15 3 +16 1 +16 3 +17 1 +17 3 +18 1 +18 3 +19 1 +19 3 +20 1 +EXPLAIN +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 2 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range a a 10 NULL 50 Using where; Using index +SELECT * FROM t3 WHERE +5 <= a AND a < 10 AND b = 3 OR +a < 5 OR +a < 10; +a b +1 0 +2 0 +3 0 +4 0 +5 0 +6 0 +7 0 +8 0 +9 0 +EXPLAIN +SELECT * FROM t3 WHERE +5 <= a AND a < 10 AND b = 3 OR +a < 5 OR +a < 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 range a a 5 NULL 8 Using where; Using index +DROP TABLE t1, t2, t3; +# +# Bug #47123: Endless 100% CPU loop with STRAIGHT_JOIN +# +CREATE TABLE t1(a INT, KEY(a)); +INSERT INTO t1 VALUES (1), (NULL); +SELECT * FROM t1 WHERE a <> NULL and (a <> NULL or a <= NULL); +a +DROP TABLE t1; +# +# Bug#47925: regression of range optimizer and date comparison in 5.1.39! +# +CREATE TABLE t1 ( a DATE, KEY ( a ) ); +CREATE TABLE t2 ( a DATETIME, KEY ( a ) ); +# Make optimizer choose range scan +INSERT INTO t1 VALUES ('2009-09-22'), ('2009-09-22'), ('2009-09-22'); +INSERT INTO t1 VALUES ('2009-09-23'), ('2009-09-23'), ('2009-09-23'); +INSERT INTO t2 VALUES ('2009-09-22 12:00:00'), ('2009-09-22 12:00:00'), +('2009-09-22 12:00:00'); +INSERT INTO t2 VALUES ('2009-09-23 12:00:00'), ('2009-09-23 12:00:00'), +('2009-09-23 12:00:00'); +# DATE vs DATE +EXPLAIN +SELECT * FROM t1 WHERE a >= '2009/09/23'; +id select_type table type possible_keys key key_len ref rows Extra +X X X range a a X X X X +SELECT * FROM t1 WHERE a >= '2009/09/23'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '20090923'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= 20090923; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009-9-23'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009.09.23'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009:09:23'; +a +2009-09-23 +2009-09-23 +2009-09-23 +# DATE vs DATETIME +EXPLAIN +SELECT * FROM t2 WHERE a >= '2009/09/23'; +id select_type table type possible_keys key key_len ref rows Extra +X X X range a a X X X X +SELECT * FROM t2 WHERE a >= '2009/09/23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009/09/23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '20090923'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= 20090923; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009-9-23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009.09.23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009:09:23'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +# DATETIME vs DATETIME +EXPLAIN +SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00'; +id select_type table type possible_keys key key_len ref rows Extra +X X X range a a X X X X +SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '20090923120000'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= 20090923120000; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009-9-23 12:00:00'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009.09.23 12:00:00'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +SELECT * FROM t2 WHERE a >= '2009:09:23 12:00:00'; +a +2009-09-23 12:00:00 +2009-09-23 12:00:00 +2009-09-23 12:00:00 +# DATETIME vs DATE +EXPLAIN +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +id select_type table type possible_keys key key_len ref rows Extra +X X X range a a X X X X +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '20090923000000'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= 20090923000000; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009-9-23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009.09.23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +SELECT * FROM t1 WHERE a >= '2009:09:23 00:00:00'; +a +2009-09-23 +2009-09-23 +2009-09-23 +# Test of the new get_date_from_str implementation +# Behavior differs slightly between the trunk and mysql-pe. +# The former may give errors for the truncated values, while the latter +# gives warnings. The purpose of this test is not to interfere, and only +# preserve existing behavior. +SELECT str_to_date('2007-10-00', '%Y-%m-%d') >= '' AND +str_to_date('2007-10-00', '%Y-%m-%d') <= '2007/10/20'; +str_to_date('2007-10-00', '%Y-%m-%d') >= '' AND +str_to_date('2007-10-00', '%Y-%m-%d') <= '2007/10/20' +1 +Warnings: +Warning 1292 Truncated incorrect date value: '' +SELECT str_to_date('2007-20-00', '%Y-%m-%d') >= '2007/10/20' AND +str_to_date('2007-20-00', '%Y-%m-%d') <= ''; +str_to_date('2007-20-00', '%Y-%m-%d') >= '2007/10/20' AND +str_to_date('2007-20-00', '%Y-%m-%d') <= '' +NULL +Warnings: +Warning 1292 Truncated incorrect date value: '' +Error 1411 Incorrect datetime value: '2007-20-00' for function str_to_date +Error 1411 Incorrect datetime value: '2007-20-00' for function str_to_date +SELECT str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20'; +str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20' +1 +Warnings: +Warning 1292 Truncated incorrect datetime value: '' +SELECT str_to_date('2007-20-00', '%Y-%m-%d') BETWEEN '2007/10/20' AND ''; +str_to_date('2007-20-00', '%Y-%m-%d') BETWEEN '2007/10/20' AND '' +NULL +Warnings: +Error 1411 Incorrect datetime value: '2007-20-00' for function str_to_date +SELECT str_to_date('', '%Y-%m-%d'); +str_to_date('', '%Y-%m-%d') +0000-00-00 +DROP TABLE t1, t2; +End of 5.1 tests diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 6b9a6b7c185..56644ebd862 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -4385,6 +4385,47 @@ id select_type table type possible_keys key key_len ref rows filtered Extra Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where ((`test`.`t1`.`a` = `test`.`t1`.`b`) and (`test`.`t1`.`a` > 1)) limit 2 DROP TABLE t1; +# +# Bug#47019: Assertion failed: 0, file .\rt_mbr.c, line 138 when +# forcing a spatial index +# +CREATE TABLE t1(a LINESTRING NOT NULL, SPATIAL KEY(a)); +INSERT INTO t1 VALUES +(GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')), +(GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')); +EXPLAIN SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +1 SIMPLE t2 ALL a NULL NULL NULL 2 +SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2; +1 +1 +1 +1 +1 +EXPLAIN SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2 FORCE INDEX(a); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 +1 SIMPLE t2 ALL a NULL NULL NULL 2 +SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2 FORCE INDEX(a); +1 +1 +1 +1 +1 +DROP TABLE t1; +# +# Bug #48291 : crash with row() operator,select into @var, and +# subquery returning multiple rows +# +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (2),(3); +# Should not crash +SELECT 1 FROM t1 WHERE a <> 1 AND NOT +ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1)) +INTO @var0; +ERROR 21000: Subquery returns more than 1 row +DROP TABLE t1; End of 5.0 tests create table t1(a INT, KEY (a)); INSERT INTO t1 VALUES (1),(2),(3),(4),(5); diff --git a/mysql-test/r/sp-bugs.result b/mysql-test/r/sp-bugs.result new file mode 100644 index 00000000000..14c5311bbe5 --- /dev/null +++ b/mysql-test/r/sp-bugs.result @@ -0,0 +1,47 @@ +# +# Bug #47412: Valgrind warnings / user can read uninitalized memory +# using SP variables +# +CREATE SCHEMA testdb; +USE testdb; +CREATE FUNCTION f2 () RETURNS INTEGER +BEGIN +DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' SET @aux = 1; +RETURN f_not_exists () ; +END| +CREATE PROCEDURE p3 ( arg1 VARCHAR(32) ) +BEGIN +CALL p_not_exists ( ); +END| +# should not return valgrind warnings +CALL p3 ( f2 () ); +ERROR 42000: PROCEDURE testdb.p_not_exists does not exist +DROP SCHEMA testdb; +CREATE SCHEMA testdb; +USE testdb; +CREATE FUNCTION f2 () RETURNS INTEGER +BEGIN +DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' SET @aux = 1; +RETURN f_not_exists () ; +END| +CREATE PROCEDURE p3 ( arg2 INTEGER ) +BEGIN +CALL p_not_exists ( ); +END| +# should not return valgrind warnings +CALL p3 ( f2 () ); +ERROR 42000: PROCEDURE testdb.p_not_exists does not exist +DROP SCHEMA testdb; +CREATE SCHEMA testdb; +USE testdb; +CREATE FUNCTION f2 () RETURNS INTEGER +BEGIN +DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' SET @aux = 1; +RETURN f_not_exists () ; +END| +# should not return valgrind warnings +SELECT f2 (); +f2 () +NULL +DROP SCHEMA testdb; +End of 5.1 tests diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 17ab2b79043..b3968ea7eb6 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1670,3 +1670,19 @@ NULL SELECT non_existent (a) FROM t1 WHERE b = 999999; ERROR 42000: FUNCTION test.non_existent does not exist DROP TABLE t1; +# +# Bug #47788: Crash in TABLE_LIST::hide_view_error on UPDATE + VIEW + +# SP + MERGE + ALTER +# +CREATE TABLE t1 (pk INT, b INT, KEY (b)); +CREATE ALGORITHM = TEMPTABLE VIEW v1 AS SELECT * FROM t1; +CREATE PROCEDURE p1 (a int) UPDATE IGNORE v1 SET b = a; +CALL p1(5); +ERROR HY000: The target table v1 of the UPDATE is not updatable +ALTER TABLE t1 CHANGE COLUMN b b2 INT; +CALL p1(7); +ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +DROP PROCEDURE p1; +DROP VIEW v1; +DROP TABLE t1; +End of 5.1 tests diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 3ad556b8c30..67514c314f4 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -6963,6 +6963,22 @@ CALL p1(); CALL p1(); DROP PROCEDURE p1; DROP TABLE t1; +# +# Bug #46629: Item_in_subselect::val_int(): Assertion `0' +# on subquery inside a SP +# +CREATE TABLE t1(a INT); +CREATE TABLE t2(a INT, b INT PRIMARY KEY); +CREATE PROCEDURE p1 () +BEGIN +SELECT a FROM t1 A WHERE A.b IN (SELECT b FROM t2 AS B); +END| +CALL p1; +ERROR 42S22: Unknown column 'A.b' in 'IN/ALL/ANY subquery' +CALL p1; +ERROR 42S22: Unknown column 'A.b' in 'IN/ALL/ANY subquery' +DROP PROCEDURE p1; +DROP TABLE t1, t2; # ------------------------------------------------------------------ # -- End of 5.1 tests # ------------------------------------------------------------------ diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index d184ae47df3..316bfcbf3f3 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -75,7 +75,7 @@ SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a)); select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1)); ERROR HY000: Incorrect usage of PROCEDURE and subquery SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1)); -ERROR HY000: Incorrect usage of PROCEDURE and subquery +ERROR HY000: Incorrect parameters to procedure 'ANALYSE' SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL; ERROR 42S22: Unknown column 'a' in 'field list' SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NOT NULL; @@ -4403,8 +4403,7 @@ FROM t1 WHERE a = 230; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables -2 DEPENDENT SUBQUERY st1 index NULL a 5 NULL 2 Using index -2 DEPENDENT SUBQUERY st2 index b b 5 NULL 2 Using where; Using index; Using join buffer +2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables SELECT MAX(b), (SELECT COUNT(*) FROM st1,st2 WHERE st2.b <= t1.b) FROM t1 WHERE a = 230; @@ -4561,4 +4560,18 @@ id g v s 51 50 NULL l 61 60 NULL l drop table t1, t2; +CREATE TABLE t1 (a ENUM('rainbow')); +INSERT INTO t1 VALUES (),(),(),(),(); +SELECT 1 FROM t1 GROUP BY (SELECT 1 FROM t1 ORDER BY AVG(LAST_INSERT_ID())); +1 +1 +DROP TABLE t1; +CREATE TABLE t1 (a LONGBLOB); +INSERT INTO t1 SET a = 'aaaa'; +INSERT INTO t1 SET a = 'aaaa'; +SELECT 1 FROM t1 GROUP BY +(SELECT LAST_INSERT_ID() FROM t1 ORDER BY MIN(a) ASC LIMIT 1); +1 +1 +DROP TABLE t1; End of 5.1 tests. diff --git a/mysql-test/r/subselect3.result b/mysql-test/r/subselect3.result index a661ec5c78b..38c9f47e0d7 100644 --- a/mysql-test/r/subselect3.result +++ b/mysql-test/r/subselect3.result @@ -895,3 +895,72 @@ t1.a < (select t4.a+10 from t4, t5 limit 2)); ERROR 21000: Subquery returns more than 1 row drop table t0, t1, t2, t3, t4, t5; +# +# BUG#48177 - SELECTs with NOT IN subqueries containing NULL +# values return too many records +# +CREATE TABLE t1 ( +i1 int DEFAULT NULL, +i2 int DEFAULT NULL +) ; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (2, 3); +INSERT INTO t1 VALUES (4, NULL); +INSERT INTO t1 VALUES (4, 0); +INSERT INTO t1 VALUES (NULL, NULL); +CREATE TABLE t2 ( +i1 int DEFAULT NULL, +i2 int DEFAULT NULL +) ; +INSERT INTO t2 VALUES (4, NULL); +INSERT INTO t2 VALUES (5, 0); + +Data in t1 +SELECT i1, i2 FROM t1; +i1 i2 +1 NULL +2 3 +4 NULL +4 0 +NULL NULL + +Data in subquery (should be filtered out) +SELECT i1, i2 FROM t2 ORDER BY i1; +i1 i2 +4 NULL +5 0 +FLUSH STATUS; + +SELECT i1, i2 +FROM t1 +WHERE (i1, i2) +NOT IN (SELECT i1, i2 FROM t2); +i1 i2 +1 NULL +2 3 + +# Check that the subquery only has to be evaluated once +# for all-NULL values even though there are two (NULL,NULL) records +# Baseline: +SHOW STATUS LIKE '%Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 17 + +INSERT INTO t1 VALUES (NULL, NULL); +FLUSH STATUS; + +SELECT i1, i2 +FROM t1 +WHERE (i1, i2) +NOT IN (SELECT i1, i2 FROM t2); +i1 i2 +1 NULL +2 3 + +# Handler_read_rnd_next should be one more than baseline +# (read record from t1, but do not read from t2) +SHOW STATUS LIKE '%Handler_read_rnd_next'; +Variable_name Value +Handler_read_rnd_next 18 +DROP TABLE t1,t2; +End of 5.1 tests diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result new file mode 100644 index 00000000000..482e0045840 --- /dev/null +++ b/mysql-test/r/subselect4.result @@ -0,0 +1,61 @@ +# +# Bug #46791: Assertion failed:(table->key_read==0),function unknown +# function,file sql_base.cc +# +CREATE TABLE t1 (a INT, b INT, KEY(a)); +INSERT INTO t1 VALUES (1,1),(2,2); +CREATE TABLE t2 LIKE t1; +INSERT INTO t2 VALUES (1,1),(2,2); +CREATE TABLE t3 LIKE t1; +# should have 1 impossible where and 2 dependent subqueries +EXPLAIN +SELECT 1 FROM t1 +WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE 1 = (SELECT MIN(t2.b) FROM t3)) +ORDER BY count(*); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 index NULL a 5 NULL 2 Using index; Using temporary +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 Using where +3 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table +# should not crash the next statement +SELECT 1 FROM t1 +WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE 1 = (SELECT MIN(t2.b) FROM t3)) +ORDER BY count(*); +1 +1 +# should not crash: the crash is caused by the previous statement +SELECT 1; +1 +1 +DROP TABLE t1,t2,t3; +# +# Bug #47106: Crash / segfault on adding EXPLAIN to a non-crashing +# query +# +CREATE TABLE t1 ( +a INT, +b INT, +PRIMARY KEY (a), +KEY b (b) +); +INSERT INTO t1 VALUES (1, 1), (2, 1); +CREATE TABLE t2 LIKE t1; +INSERT INTO t2 SELECT * FROM t1; +CREATE TABLE t3 LIKE t1; +INSERT INTO t3 SELECT * FROM t1; +# Should not crash. +# Should have 1 impossible where and 2 dependent subqs. +EXPLAIN +SELECT +(SELECT 1 FROM t1,t2 WHERE t2.b > t3.b) +FROM t3 WHERE 1 = 0 GROUP BY 1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 DEPENDENT SUBQUERY t1 index NULL PRIMARY 4 NULL 2 Using index +2 DEPENDENT SUBQUERY t2 index b b 5 NULL 2 Using where; Using index; Using join buffer +# should return 0 rows +SELECT +(SELECT 1 FROM t1,t2 WHERE t2.b > t3.b) +FROM t3 WHERE 1 = 0 GROUP BY 1; +(SELECT 1 FROM t1,t2 WHERE t2.b > t3.b) +DROP TABLE t1,t2,t3; +End of 5.0 tests. diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index e252331cd1a..17fd95ab1c8 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -161,7 +161,7 @@ procs_priv CREATE TABLE `procs_priv` ( `Host` char(60) COLLATE utf8_bin NOT NULL DEFAULT '', `Db` char(64) COLLATE utf8_bin NOT NULL DEFAULT '', `User` char(16) COLLATE utf8_bin NOT NULL DEFAULT '', - `Routine_name` char(64) COLLATE utf8_bin NOT NULL DEFAULT '', + `Routine_name` char(64) CHARACTER SET utf8 NOT NULL DEFAULT '', `Routine_type` enum('FUNCTION','PROCEDURE') COLLATE utf8_bin NOT NULL, `Grantor` char(77) COLLATE utf8_bin NOT NULL DEFAULT '', `Proc_priv` set('Execute','Alter Routine','Grant') CHARACTER SET utf8 NOT NULL DEFAULT '', diff --git a/mysql-test/r/trigger_notembedded.result b/mysql-test/r/trigger_notembedded.result index 335e6910a3a..d66308a9bd7 100644 --- a/mysql-test/r/trigger_notembedded.result +++ b/mysql-test/r/trigger_notembedded.result @@ -180,8 +180,6 @@ NULL mysqltest_db1 trg5 DELETE NULL mysqltest_db1 t1 0 NULL SET @a = 5 ROW BEFOR DROP USER mysqltest_dfn@localhost; DROP USER mysqltest_inv@localhost; DROP DATABASE mysqltest_db1; -Warnings: -Warning 1454 No definer attribute for trigger 'mysqltest_db1'.'trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%'; DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%'; DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%'; diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result index b831771d9c5..51feab0a421 100644 --- a/mysql-test/r/type_bit.result +++ b/mysql-test/r/type_bit.result @@ -749,6 +749,16 @@ bin(a1) 110000111111111 110001011111111 drop table t1bit7, t2bit7; +# +# Bug42803: Field_bit does not have unsigned_flag field, +# can lead to bad memory access +# +CREATE TABLE t1 (a BIT(7), b BIT(9), KEY(a, b)); +INSERT INTO t1 VALUES(0, 0), (5, 3), (5, 6), (6, 4), (7, 0); +EXPLAIN SELECT a+0, b+0 FROM t1 WHERE a > 4 and b < 7 ORDER BY 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 2 NULL 4 Using where; Using index; Using filesort +DROP TABLE t1; End of 5.0 tests create table t1(a bit(7)); insert into t1 values(0x40); diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index c3d1e400b23..748aadee4fb 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -1495,9 +1495,9 @@ CREATE TABLE t1 (a int DEFAULT NULL, b int DEFAULT NULL); INSERT INTO t1 VALUES (3,30), (1,10), (2,10); SELECT a+CAST(1 AS decimal(65,30)) AS aa, SUM(b) FROM t1 GROUP BY aa; aa SUM(b) -2.00000000000000000000000000000 10 -3.00000000000000000000000000000 10 -4.00000000000000000000000000000 30 +2.000000000000000000000000000000 10 +3.000000000000000000000000000000 10 +4.000000000000000000000000000000 30 SELECT a+CAST(1 AS decimal(65,31)) AS aa, SUM(b) FROM t1 GROUP BY aa; ERROR 42000: Too big scale 31 specified for column '1'. Maximum is 30. DROP TABLE t1; @@ -1521,13 +1521,13 @@ f1 DROP TABLE t1; CREATE TABLE t1 SELECT 123451234512345123451234512345123451234512345.678906789067890678906789067890678906789067890 AS f1; Warnings: -Note 1265 Data truncated for column 'f1' at row 1 +Warning 1264 Out of range value for column 'f1' at row 1 DESC t1; Field Type Null Key Default Extra -f1 decimal(65,20) NO 0.00000000000000000000 +f1 decimal(65,30) NO 0.000000000000000000000000000000 SELECT f1 FROM t1; f1 -123451234512345123451234512345123451234512345.67890678906789067891 +99999999999999999999999999999999999.999999999999999999999999999999 DROP TABLE t1; select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 * 1.01500000 * 1.01500000 * 0.99500000); @@ -1595,7 +1595,7 @@ Warnings: Note 1265 Data truncated for column 'my_col' at row 1 DESCRIBE t1; Field Type Null Key Default Extra -my_col decimal(32,30) NO 0.000000000000000000000000000000 +my_col decimal(65,30) NO 0.000000000000000000000000000000 SELECT my_col FROM t1; my_col 1.123456789123456789123456789123 @@ -1625,212 +1625,8 @@ Warnings: Note 1265 Data truncated for column 'my_col' at row 1 DESCRIBE t1; Field Type Null Key Default Extra -my_col decimal(30,30) YES NULL +my_col decimal(65,30) YES NULL SELECT my_col FROM t1; my_col 0.012345687012345687012345687012 DROP TABLE t1; -# -# Bug#45261: Crash, stored procedure + decimal -# -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 SELECT -/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001 -AS c1; -Warnings: -Warning 1264 Out of range value for column 'c1' at row 1 -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,0) NO 0 -SELECT * FROM t1; -c1 -99999999999999999999999999999999999999999999999999999999999999999 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001. -AS c1; -Warnings: -Warning 1264 Out of range value for column 'c1' at row 1 -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,0) NO 0 -SELECT * FROM t1; -c1 -99999999999999999999999999999999999999999999999999999999999999999 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.1 /* 1 */ -AS c1; -Warnings: -Warning 1264 Out of range value for column 'c1' at row 1 -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,0) NO 0 -SELECT * FROM t1; -c1 -99999999999999999999999999999999999999999999999999999999999999999 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001 -AS c1; -Warnings: -Error 1292 Truncated incorrect DECIMAL value: '' -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,0) NO 0 -SELECT * FROM t1; -c1 -99999999999999999999999999999999999999999999999999999999999999999 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 40 */ 1000000000000000000000000000000000000001.1000000000000000000000000000000000000001 /* 40 */ -AS c1; -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,25) NO 0.0000000000000000000000000 -SELECT * FROM t1; -c1 -1000000000000000000000000000000000000001.1000000000000000000000000 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 1 */ 1.10000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 80 */ -AS c1; -DESC t1; -Field Type Null Key Default Extra -c1 decimal(31,30) NO 0.000000000000000000000000000000 -SELECT * FROM t1; -c1 -1.100000000000000000000000000000 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 1 */ 1.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ -AS c1; -DESC t1; -Field Type Null Key Default Extra -c1 decimal(31,30) NO 0.000000000000000000000000000000 -SELECT * FROM t1; -c1 -1.100000000000000000000000000000 -DROP TABLE t1; -CREATE TABLE t1 SELECT -.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ -AS c1; -Warnings: -Note 1265 Data truncated for column 'c1' at row 1 -DESC t1; -Field Type Null Key Default Extra -c1 decimal(30,30) NO 0.000000000000000000000000000000 -SELECT * FROM t1; -c1 -0.100000000000000000000000000000 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 45 */ 123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345 /* 45 */ -AS c1; -Warnings: -Note 1265 Data truncated for column 'c1' at row 1 -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,20) NO 0.00000000000000000000 -SELECT * FROM t1; -c1 -123456789012345678901234567890123456789012345.12345678901234567890 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 65 */ 12345678901234567890123456789012345678901234567890123456789012345.1 /* 1 */ -AS c1; -Warnings: -Note 1265 Data truncated for column 'c1' at row 1 -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,0) NO 0 -SELECT * FROM t1; -c1 -12345678901234567890123456789012345678901234567890123456789012345 -DROP TABLE t1; -CREATE TABLE t1 SELECT -/* 66 */ 123456789012345678901234567890123456789012345678901234567890123456.1 /* 1 */ -AS c1; -Warnings: -Warning 1264 Out of range value for column 'c1' at row 1 -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,0) NO 0 -SELECT * FROM t1; -c1 -99999999999999999999999999999999999999999999999999999999999999999 -DROP TABLE t1; -CREATE TABLE t1 SELECT -.123456789012345678901234567890123456789012345678901234567890123456 /* 66 */ -AS c1; -Warnings: -Note 1265 Data truncated for column 'c1' at row 1 -DESC t1; -Field Type Null Key Default Extra -c1 decimal(30,30) NO 0.000000000000000000000000000000 -SELECT * FROM t1; -c1 -0.123456789012345678901234567890 -DROP TABLE t1; -CREATE TABLE t1 AS SELECT 123.1234567890123456789012345678901 /* 31 */ AS c1; -Warnings: -Note 1265 Data truncated for column 'c1' at row 1 -DESC t1; -Field Type Null Key Default Extra -c1 decimal(33,30) NO 0.000000000000000000000000000000 -SELECT * FROM t1; -c1 -123.123456789012345678901234567890 -DROP TABLE t1; -CREATE TABLE t1 SELECT 1.1 + CAST(1 AS DECIMAL(65,30)) AS c1; -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,29) NO 0.00000000000000000000000000000 -SELECT * FROM t1; -c1 -2.10000000000000000000000000000 -DROP TABLE t1; -# -# Test that the integer and decimal parts are properly calculated. -# -CREATE TABLE t1 (a DECIMAL(30,30)); -INSERT INTO t1 VALUES (0.1),(0.2),(0.3); -CREATE TABLE t2 SELECT MIN(a + 0.0000000000000000000000000000001) AS c1 FROM t1; -Warnings: -Note 1265 Data truncated for column 'c1' at row 3 -DESC t2; -Field Type Null Key Default Extra -c1 decimal(32,30) YES NULL -DROP TABLE t1,t2; -CREATE TABLE t1 (a DECIMAL(30,30)); -INSERT INTO t1 VALUES (0.1),(0.2),(0.3); -CREATE TABLE t2 SELECT IFNULL(a + 0.0000000000000000000000000000001, NULL) AS c1 FROM t1; -Warnings: -Note 1265 Data truncated for column 'c1' at row 1 -Note 1265 Data truncated for column 'c1' at row 2 -Note 1265 Data truncated for column 'c1' at row 3 -DESC t2; -Field Type Null Key Default Extra -c1 decimal(32,30) YES NULL -DROP TABLE t1,t2; -CREATE TABLE t1 (a DECIMAL(30,30)); -INSERT INTO t1 VALUES (0.1),(0.2),(0.3); -CREATE TABLE t2 SELECT CASE a WHEN 0.1 THEN 0.0000000000000000000000000000000000000000000000000000000000000000001 END AS c1 FROM t1; -Warnings: -Note 1265 Data truncated for column 'c1' at row 1 -DESC t2; -Field Type Null Key Default Extra -c1 decimal(31,30) YES NULL -DROP TABLE t1,t2; -# -# Test that variables get maximum precision. -# -SET @decimal= 1.1; -CREATE TABLE t1 SELECT @decimal AS c1; -DESC t1; -Field Type Null Key Default Extra -c1 decimal(65,30) YES NULL -SELECT * FROM t1; -c1 -1.100000000000000000000000000000 -DROP TABLE t1; diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result index 15410ac2039..601b364fbbe 100644 --- a/mysql-test/r/udf.result +++ b/mysql-test/r/udf.result @@ -392,4 +392,20 @@ a 4 DROP FUNCTION sequence; DROP TABLE t1,t2; +# +# Bug#46259: 5.0.83 -> 5.1.36, query doesn't work +# +CREATE TABLE t1 ( a INT ); +INSERT INTO t1 VALUES (1), (2), (3); +SELECT IF( a = 1, a, a ) AS `b` FROM t1 ORDER BY field( `b` + 1, 1 ); +b +1 +2 +3 +SELECT IF( a = 1, a, a ) AS `b` FROM t1 ORDER BY field( `b`, 1 ); +b +2 +3 +1 +DROP TABLE t1; End of 5.0 tests. diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index 7a51649fac5..d859579e835 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -503,3 +503,14 @@ ERROR HY000: Recursive stored functions and triggers are not allowed. DROP TABLE t1; DROP FUNCTION f1; End of 5.0 tests +# +# Bug #47919 assert in open_table during ALTER temporary table +# +CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT, PRIMARY KEY (f1)); +CREATE TEMPORARY TABLE t2 LIKE t1; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); +ALTER TABLE t2 COMMENT = 'ABC'; +UPDATE t2, t1 SET t2.f1 = 2, t1.f1 = 9; +ALTER TABLE t2 COMMENT = 'DEF'; +DROP TABLE t1, t2; diff --git a/mysql-test/r/upgrade.result b/mysql-test/r/upgrade.result index da6201692a9..034242079b1 100644 --- a/mysql-test/r/upgrade.result +++ b/mysql-test/r/upgrade.result @@ -108,11 +108,7 @@ a-b-c show create view `a-b-c`.v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `a`.`f1` AS `f1` from (`a-b-c`.`t1` `a` join `information_schema`.`tables` `b`) where (convert(`a`.`f1` using utf8) = `b`.`TABLE_NAME`) utf8 utf8_general_ci -Warnings: -Note 1600 Creation context of view `a-b-c`.`v1' is invalid select * from `a-b-c`.v1; f1 -Warnings: -Note 1600 Creation context of view `a-b-c`.`v1' is invalid drop database `a-b-c`; use test; diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 7e280fa2fe5..2d5c515d0b5 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -606,7 +606,7 @@ SHOW CREATE VIEW v; View Create View character_set_client collation_connection v CREATE ALGORITHM=UNDEFINED DEFINER=`no-such-user`@`localhost` SQL SECURITY DEFINER VIEW `v` AS select `test`.`t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'test.v' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no-such-user'@'localhost') does not exist SELECT * FROM v; ERROR HY000: The user specified as a definer ('no-such-user'@'localhost') does not exist DROP VIEW v; @@ -963,7 +963,7 @@ SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1; Warnings: Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist @@ -971,7 +971,7 @@ SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=MERGE DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist ALTER ALGORITHM=TEMPTABLE DEFINER=no_such@user_2 VIEW v1 AS SELECT * FROM t1; Warnings: Note 1449 The user specified as a definer ('no_such'@'user_2') does not exist @@ -979,7 +979,7 @@ SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=TEMPTABLE DEFINER=`no_such`@`user_2` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such'@'user_2') does not exist DROP VIEW v1; DROP TABLE t1; CREATE USER mysqluser1@localhost; @@ -1044,3 +1044,196 @@ DROP DATABASE mysqltest1; DROP VIEW test.v3; DROP USER mysqluser1@localhost; USE test; +# +# Bug#35996: SELECT + SHOW VIEW should be enough to display view +# definition +# +CREATE USER mysqluser1@localhost; +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; +GRANT USAGE, SELECT, CREATE VIEW, SHOW VIEW +ON mysqltest2.* TO mysqluser1@localhost; +USE mysqltest1; +CREATE TABLE t1( a INT ); +CREATE TABLE t2( a INT, b INT ); +CREATE FUNCTION f1() RETURNS INT RETURN 1; +CREATE VIEW v1 AS SELECT 1 AS a; +CREATE VIEW v2 AS SELECT 1 AS a, 2 AS b; +GRANT SELECT ON TABLE t1 TO mysqluser1@localhost; +GRANT SELECT (a, b) ON TABLE t2 TO mysqluser1@localhost; +GRANT EXECUTE ON FUNCTION f1 TO mysqluser1@localhost; +GRANT SELECT ON TABLE v1 TO mysqluser1@localhost; +GRANT SELECT (a, b) ON TABLE v2 TO mysqluser1@localhost; +CREATE VIEW v_t1 AS SELECT * FROM t1; +CREATE VIEW v_t2 AS SELECT * FROM t2; +CREATE VIEW v_f1 AS SELECT f1() AS a; +CREATE VIEW v_v1 AS SELECT * FROM v1; +CREATE VIEW v_v2 AS SELECT * FROM v2; +GRANT SELECT, SHOW VIEW ON v_t1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_t2 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_f1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_v1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_v2 TO mysqluser1@localhost; +CREATE VIEW v_mysqluser1_t1 AS SELECT * FROM mysqltest1.t1; +CREATE VIEW v_mysqluser1_t2 AS SELECT * FROM mysqltest1.t2; +CREATE VIEW v_mysqluser1_f1 AS SELECT mysqltest1.f1() AS a; +CREATE VIEW v_mysqluser1_v1 AS SELECT * FROM mysqltest1.v1; +CREATE VIEW v_mysqluser1_v2 AS SELECT * FROM mysqltest1.v2; +SHOW CREATE VIEW mysqltest1.v_t1; +View Create View character_set_client collation_connection +v_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_t2; +View Create View character_set_client collation_connection +v_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_f1; +View Create View character_set_client collation_connection +v_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_f1` AS select `f1`() AS `a` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_v1; +View Create View character_set_client collation_connection +v_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_v2; +View Create View character_set_client collation_connection +v_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t1; +View Create View character_set_client collation_connection +v_mysqluser1_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t2; +View Create View character_set_client collation_connection +v_mysqluser1_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_f1; +View Create View character_set_client collation_connection +v_mysqluser1_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_f1` AS select `mysqltest1`.`f1`() AS `a` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_v1; +View Create View character_set_client collation_connection +v_mysqluser1_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_v2; +View Create View character_set_client collation_connection +v_mysqluser1_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +REVOKE SELECT ON TABLE t1 FROM mysqluser1@localhost; +REVOKE SELECT (a) ON TABLE t2 FROM mysqluser1@localhost; +REVOKE EXECUTE ON FUNCTION f1 FROM mysqluser1@localhost; +REVOKE SELECT ON TABLE v1 FROM mysqluser1@localhost; +SHOW CREATE VIEW mysqltest1.v_t1; +View Create View character_set_client collation_connection +v_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_t2; +View Create View character_set_client collation_connection +v_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_f1; +View Create View character_set_client collation_connection +v_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_f1` AS select `f1`() AS `a` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_v1; +View Create View character_set_client collation_connection +v_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_v2; +View Create View character_set_client collation_connection +v_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t1; +View Create View character_set_client collation_connection +v_mysqluser1_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t2; +View Create View character_set_client collation_connection +v_mysqluser1_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_f1; +View Create View character_set_client collation_connection +v_mysqluser1_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_f1` AS select `mysqltest1`.`f1`() AS `a` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_v1; +View Create View character_set_client collation_connection +v_mysqluser1_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_v2; +View Create View character_set_client collation_connection +v_mysqluser1_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +# Testing the case when the views reference missing objects. +# Obviously, there are no privileges to check for, so we +# need only each object type once. +DROP TABLE t1; +DROP FUNCTION f1; +DROP VIEW v1; +SHOW CREATE VIEW mysqltest1.v_t1; +View Create View character_set_client collation_connection +v_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW mysqltest1.v_f1; +View Create View character_set_client collation_connection +v_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_f1` AS select `f1`() AS `a` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest1.v_f1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW mysqltest1.v_v1; +View Create View character_set_client collation_connection +v_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest1.v_v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_t1; +View Create View character_set_client collation_connection +v_mysqluser1_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_f1; +View Create View character_set_client collation_connection +v_mysqluser1_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_f1` AS select `mysqltest1`.`f1`() AS `a` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_f1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_v1; +View Create View character_set_client collation_connection +v_mysqluser1_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +REVOKE SHOW VIEW ON v_t1 FROM mysqluser1@localhost; +REVOKE SHOW VIEW ON v_f1 FROM mysqluser1@localhost; +REVOKE SHOW VIEW ON v_v1 FROM mysqluser1@localhost; +SHOW CREATE VIEW mysqltest1.v_t1; +ERROR 42000: SHOW VIEW command denied to user 'mysqluser1'@'localhost' for table 'v_t1' +SHOW CREATE VIEW mysqltest1.v_f1; +ERROR 42000: SHOW VIEW command denied to user 'mysqluser1'@'localhost' for table 'v_f1' +SHOW CREATE VIEW mysqltest1.v_v1; +ERROR 42000: SHOW VIEW command denied to user 'mysqluser1'@'localhost' for table 'v_v1' +SHOW CREATE VIEW v_mysqluser1_t1; +View Create View character_set_client collation_connection +v_mysqluser1_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_f1; +View Create View character_set_client collation_connection +v_mysqluser1_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_f1` AS select `mysqltest1`.`f1`() AS `a` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_f1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_v1; +View Create View character_set_client collation_connection +v_mysqluser1_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +DROP USER mysqluser1@localhost; +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; +USE test; +CREATE TABLE t1( a INT ); +CREATE DEFINER = no_such_user@no_such_host VIEW v1 AS SELECT * FROM t1; +Warnings: +Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such_user`@`no_such_host` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci +Warnings: +Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist +DROP TABLE t1; +DROP VIEW v1; +# +# Bug #46019: ERROR 1356 When selecting from within another +# view that has Group By +# +CREATE DATABASE mysqltest1; +USE mysqltest1; +CREATE TABLE t1 (a INT); +CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT a FROM t1 GROUP BY a; +CREATE SQL SECURITY INVOKER VIEW v2 AS SELECT a FROM v1; +CREATE USER mysqluser1; +GRANT SELECT ON TABLE t1 TO mysqluser1; +GRANT SELECT, SHOW VIEW ON TABLE v1 TO mysqluser1; +GRANT SELECT, SHOW VIEW ON TABLE v2 TO mysqluser1; +SELECT a FROM v1; +a +SELECT a FROM v2; +a +DROP USER mysqluser1; +DROP DATABASE mysqltest1; diff --git a/mysql-test/r/warnings.result b/mysql-test/r/warnings.result index 2e393aea9e4..8a87852d582 100644 --- a/mysql-test/r/warnings.result +++ b/mysql-test/r/warnings.result @@ -313,4 +313,9 @@ ERROR 22001: Data too long for column 'c_tinytext' at row 1 insert into t2 values(@q); ERROR 22001: Data too long for column 'c_tinyblob' at row 1 drop table t1, t2; +DROP TABLE t1; +ERROR 42S02: Unknown table 't1' +SHOW ERRORS; +Level Code Message +Error 1051 Unknown table 't1' End of 5.0 tests diff --git a/mysql-test/r/windows.result b/mysql-test/r/windows.result index 4e0d73ea0eb..d0cdd858d4a 100644 --- a/mysql-test/r/windows.result +++ b/mysql-test/r/windows.result @@ -53,3 +53,10 @@ ERROR HY000: No paths allowed for shared library execute abc; ERROR HY000: No paths allowed for shared library deallocate prepare abc; +# +# Bug#45498: Socket variable not available on Windows +# +SELECT VARIABLE_NAME FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME = 'socket'; +VARIABLE_NAME +SOCKET diff --git a/mysql-test/r/xa.result b/mysql-test/r/xa.result index a597806d897..d23c8e672b0 100644 --- a/mysql-test/r/xa.result +++ b/mysql-test/r/xa.result @@ -89,3 +89,28 @@ xa start 'a'; xa end 'a'; xa prepare 'a'; xa commit 'a'; +CREATE TABLE t1(a INT, KEY(a)) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1),(2); +BEGIN; +UPDATE t1 SET a=3 WHERE a=1; +BEGIN; +UPDATE t1 SET a=4 WHERE a=2; +UPDATE t1 SET a=5 WHERE a=2; +UPDATE t1 SET a=5 WHERE a=1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +ROLLBACK; +ROLLBACK; +BEGIN; +UPDATE t1 SET a=3 WHERE a=1; +XA START 'xid1'; +UPDATE t1 SET a=4 WHERE a=2; +UPDATE t1 SET a=5 WHERE a=2; +UPDATE t1 SET a=5 WHERE a=1; +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +XA END 'xid1'; +ERROR XA102: XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected +XA ROLLBACK 'xid1'; +XA START 'xid1'; +XA END 'xid1'; +XA ROLLBACK 'xid1'; +DROP TABLE t1; diff --git a/mysql-test/std_data/Index.xml b/mysql-test/std_data/Index.xml index 988dddcc68a..3dc647d8195 100644 --- a/mysql-test/std_data/Index.xml +++ b/mysql-test/std_data/Index.xml @@ -68,4 +68,17 @@ </charset> + <charset name="latin1"> + <family>Western</family> + <description>cp1252 West European</description> + <alias>csisolatin1</alias> + <alias>iso-8859-1</alias> + <alias>iso-ir-100</alias> + <alias>iso_8859-1</alias> + <alias>iso_8859-1:1987</alias> + <alias>l1</alias> + <alias>latin1</alias> + <collation name="latin1_test" id="99" order="test"/> + </charset> + </charsets> diff --git a/mysql-test/std_data/binlog_transaction.000001 b/mysql-test/std_data/binlog_transaction.000001 Binary files differnew file mode 100644 index 00000000000..c1d0745d57c --- /dev/null +++ b/mysql-test/std_data/binlog_transaction.000001 diff --git a/mysql-test/std_data/latin1.xml b/mysql-test/std_data/latin1.xml new file mode 100644 index 00000000000..458b1c34da1 --- /dev/null +++ b/mysql-test/std_data/latin1.xml @@ -0,0 +1,135 @@ +<?xml version='1.0' encoding="utf-8"?> + +<charsets> + +<copyright> + Copyright (C) 2009 Sun Microsystems, Inc + + 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 +</copyright> + +<charset name="latin1"> + +<ctype> +<map> + 00 + 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20 + 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 + 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10 + 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10 + 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20 + 10 00 10 02 10 10 10 10 10 10 01 10 01 00 01 00 + 00 10 10 10 10 10 10 10 10 10 02 10 02 00 02 01 + 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 + 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 02 +</map> +</ctype> + + +<lower> +<map> + 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F + 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F + 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F + 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F + 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F + 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F + 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F + 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F + 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F + 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F + A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF +</map> +</lower> + + +<upper> +<map> + 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F + 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F + 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F + 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F + 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F + 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F + 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F + 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F + 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F + 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F + A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF +</map> +</upper> + + +<unicode> +<map> + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 20AC 0081 201A 0192 201E 2026 2020 2021 02C6 2030 0160 2039 0152 008D 017D 008F + 0090 2018 2019 201C 201D 2022 2013 2014 02DC 2122 0161 203A 0153 009D 017E 0178 + 00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF + 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF + 00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF + 00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF + 00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF + 00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF +</map> +</unicode> + +<collation name="latin1_test"> +<map> + 00 01 02 03 37 2D 2E 2F 16 05 25 0B 0C 0D 0E 0F + 10 11 12 13 3C 3D 32 26 18 19 3F 27 1C 1D 1E 1F + 40 4F 7F 7B 5B 6C 50 7D 4D 5D 5C 4E 6B 60 4B 61 + F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 7A 5E 4C 7E 6E 6F + 7C C1 C2 C3 C4 C5 C6 C7 C8 C9 D1 D2 D3 D4 D5 D6 + D7 D8 D9 E2 E3 E4 E5 E6 E7 E8 E9 4A E0 5A 5F 6D + 79 81 82 83 84 85 86 87 88 89 91 92 93 94 95 96 + 97 98 99 A2 A3 A4 A5 A6 A7 A8 A9 C0 6A D0 A1 07 + 20 21 22 23 24 15 06 17 28 29 2A 2B 2C 09 0A 1B + 30 31 1A 33 34 35 36 08 38 39 3A 3B 04 14 3E E1 + 41 42 43 44 45 46 47 48 49 51 52 53 54 55 56 57 + 58 59 62 63 64 65 66 67 68 69 70 71 72 73 74 75 + 76 77 78 80 8A 8B 8C 8D 8E 8F 90 9A 9B 9C 9D 9E + 9F A0 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 + B8 B9 BA BB BC BD BE BF CA CB CC CD CE CF DA DB + DC DD DE DF EA EB EC ED EE EF FA FB FC FD FE FF +</map> +</collation> + +</charset> + +</charsets> diff --git a/mysql-test/suite/binlog/r/binlog_delete_and_flush_index.result b/mysql-test/suite/binlog/r/binlog_delete_and_flush_index.result new file mode 100644 index 00000000000..036ccf131bb --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_delete_and_flush_index.result @@ -0,0 +1,50 @@ +RESET MASTER; +CREATE TABLE t1 (a int); +### assertion: index file contains regular entries +SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index'); +SELECT @index; +@index +master-bin.000001 + +### assertion: show original binlogs +show binary logs; +Log_name File_size +master-bin.000001 # +### assertion: binlog contents from regular entries +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a int) +FLUSH LOGS; +### assertion: index file contains renamed binlog and the new one +SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index'); +SELECT @index; +@index +master-bin-b34582.000001 +master-bin.000002 + +### assertion: original binlog content still exists, despite we +### renamed and changed the index file +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin-b34582.000001 # Query # # use `test`; CREATE TABLE t1 (a int) +### assertion: user changed binlog index shows correct entries +show binary logs; +Log_name File_size +master-bin-b34582.000001 # +master-bin.000002 # +DROP TABLE t1; +### assertion: purging binlogs up to binlog created after instrumenting index file should work +PURGE BINARY LOGS TO 'master-bin.000002'; +### assertion: show binary logs should only contain latest binlog +show binary logs; +Log_name File_size +master-bin.000002 # +### assertion: assert that binlog files were indeed purged (using file_exists calls) +### assertion: assert that not purged binlog file exists +### assertion: show index file contents and these should match show binary logs issued above +SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index'); +SELECT @index; +@index +master-bin.000002 + +RESET MASTER; diff --git a/mysql-test/suite/binlog/r/binlog_killed_simulate.result b/mysql-test/suite/binlog/r/binlog_killed_simulate.result index 634d3f62814..df04f5129cf 100644 --- a/mysql-test/suite/binlog/r/binlog_killed_simulate.result +++ b/mysql-test/suite/binlog/r/binlog_killed_simulate.result @@ -19,7 +19,7 @@ ERROR 70100: Query execution was interrupted show binlog events from <binlog_start>; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# -master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/rpl_loaddata.dat' into table t2 /* will be "killed" in the middle */ ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t2` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a, b) ;file_id=# select (@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog")) is not null; diff --git a/mysql-test/suite/binlog/r/binlog_mixed_failure_mixing_engines.result b/mysql-test/suite/binlog/r/binlog_mixed_failure_mixing_engines.result new file mode 100644 index 00000000000..dfc08d76a6a --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_mixed_failure_mixing_engines.result @@ -0,0 +1,406 @@ +################################################################################### +# CONFIGURATION +################################################################################### +CREATE TABLE nt_1 (a text, b int PRIMARY KEY) ENGINE = MyISAM; +CREATE TABLE nt_2 (a text, b int PRIMARY KEY) ENGINE = MyISAM; +CREATE TABLE tt_1 (a text, b int PRIMARY KEY) ENGINE = Innodb; +CREATE TABLE tt_2 (a text, b int PRIMARY KEY) ENGINE = Innodb; +CREATE TRIGGER tr_i_tt_1_to_nt_1 BEFORE INSERT ON tt_1 FOR EACH ROW +BEGIN +INSERT INTO nt_1 VALUES (NEW.a, NEW.b); +END| +CREATE TRIGGER tr_i_nt_2_to_tt_2 BEFORE INSERT ON nt_2 FOR EACH ROW +BEGIN +INSERT INTO tt_2 VALUES (NEW.a, NEW.b); +END| +################################################################################### +# CHECK HISTORY IN BINLOG +################################################################################### + + + +*** "B M* T C" with error in M* generates in the binlog the "B M* R B T C" entries + +INSERT INTO nt_1 VALUES ("new text 1", 1); +BEGIN; +INSERT INTO tt_1 VALUES (USER(), 2), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 3", 3); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; INSERT INTO nt_1 VALUES ("new text 1", 1) +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 3", 3) +master-bin.000001 # Xid # # COMMIT /* XID */ + +INSERT INTO tt_2 VALUES ("new text 4", 4); +BEGIN; +INSERT INTO nt_2 VALUES (USER(), 5), (USER(), 4); +ERROR 23000: Duplicate entry '4' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 6", 6); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 4", 4) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 6", 6) +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B M M* T C" with error in M* generates in the binlog the "B M M* T C" entries + +INSERT INTO nt_1 VALUES ("new text 10", 10); +BEGIN; +INSERT INTO tt_1 VALUES ("new text 7", 7), ("new text 8", 8); +INSERT INTO tt_1 VALUES (USER(), 9), (USER(), 10); +ERROR 23000: Duplicate entry '10' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 11", 11); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; INSERT INTO nt_1 VALUES ("new text 10", 10) +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_1 VALUES ("new text 7", 7), ("new text 8", 8) +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 11", 11) +master-bin.000001 # Xid # # COMMIT /* XID */ + +INSERT INTO tt_2 VALUES ("new text 15", 15); +BEGIN; +INSERT INTO nt_2 VALUES ("new text 12", 12), ("new text 13", 13); +INSERT INTO nt_2 VALUES (USER(), 14), (USER(), 15); +ERROR 23000: Duplicate entry '15' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 16", 16); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 15", 15) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO nt_2 VALUES ("new text 12", 12), ("new text 13", 13) +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 16", 16) +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B M* M* T C" with error in M* generates in the binlog the "B M* R B M* R B T C" entries + +INSERT INTO nt_1 VALUES ("new text 18", 18); +INSERT INTO nt_1 VALUES ("new text 20", 20); +BEGIN; +INSERT INTO tt_1 VALUES (USER(), 17), (USER(), 18); +ERROR 23000: Duplicate entry '18' for key 'PRIMARY' +INSERT INTO tt_1 VALUES (USER(), 19), (USER(), 20); +ERROR 23000: Duplicate entry '20' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 21", 21); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; INSERT INTO nt_1 VALUES ("new text 18", 18) +master-bin.000001 # Query # # use `test`; INSERT INTO nt_1 VALUES ("new text 20", 20) +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 21", 21) +master-bin.000001 # Xid # # COMMIT /* XID */ + +INSERT INTO tt_2 VALUES ("new text 23", 23); +INSERT INTO tt_2 VALUES ("new text 25", 25); +BEGIN; +INSERT INTO nt_2 VALUES (USER(), 22), (USER(), 23); +ERROR 23000: Duplicate entry '23' for key 'PRIMARY' +INSERT INTO nt_2 VALUES (USER(), 24), (USER(), 25); +ERROR 23000: Duplicate entry '25' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 26", 26); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 23", 23) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 25", 25) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 26", 26) +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B T INSERT M...SELECT* C" with an error in INSERT M...SELECT* generates +*** in the binlog the following entries: "Nothing". +*** There is a bug in that will be fixed after WL#2687. Please, check BUG#47175 for further details. + +TRUNCATE TABLE nt_2; +TRUNCATE TABLE tt_2; +INSERT INTO tt_2 VALUES ("new text 7", 7); +BEGIN; +INSERT INTO tt_2 VALUES ("new text 27", 27); +INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; +ERROR 23000: Duplicate entry '7' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 28", 28); +ROLLBACK; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE nt_2 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE tt_2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 7", 7) +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B INSERT M..SELECT* C" with an error in INSERT M...SELECT* generates +*** in the binlog the following entries: "B INSERT M..SELECT* R". + +TRUNCATE TABLE nt_2; +TRUNCATE TABLE tt_2; +INSERT INTO tt_2 VALUES ("new text 7", 7); +BEGIN; +INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; +ERROR 23000: Duplicate entry '7' for key 'PRIMARY' +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE nt_2 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE tt_2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO tt_2 VALUES ("new text 7", 7) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK + + + +*** "B N N T C" generates in the binlog the "B N C B N C B T C" entries + +TRUNCATE TABLE nt_1; +TRUNCATE TABLE tt_2; +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 1); +INSERT INTO nt_1 VALUES (USER(), 2); +INSERT INTO tt_2 VALUES (USER(), 3); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE nt_1 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE tt_2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B N N T R" generates in the binlog the "B N C B N C B T R" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 4); +INSERT INTO nt_1 VALUES (USER(), 5); +INSERT INTO tt_2 VALUES (USER(), 6); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK + + + +*** "B N* N* T C" with error in N* generates in the binlog the "B N R B N R B T C" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 7), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO nt_1 VALUES (USER(), 8), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO tt_2 VALUES (USER(), 9); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B N* N* T R" with error in N* generates in the binlog the "B N R B N R B T R" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 10), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO nt_1 VALUES (USER(), 11), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO tt_2 VALUES (USER(), 12); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK + + + +*** "B N N T N T C" generates in the binlog the "B N C B N C B T N T C" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 13); +INSERT INTO nt_1 VALUES (USER(), 14); +INSERT INTO tt_2 VALUES (USER(), 15); +INSERT INTO nt_1 VALUES (USER(), 16); +INSERT INTO tt_2 VALUES (USER(), 17); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B N N T N T R" generates in the binlog the "B N C B N C B T N T R" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 18); +INSERT INTO nt_1 VALUES (USER(), 19); +INSERT INTO tt_2 VALUES (USER(), 20); +INSERT INTO nt_1 VALUES (USER(), 21); +INSERT INTO tt_2 VALUES (USER(), 22); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +################################################################################### +# CLEAN +################################################################################### +DROP TABLE tt_1; +DROP TABLE tt_2; +DROP TABLE nt_1; +DROP TABLE nt_2; diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result index f6b5392dbc8..4d32a4f4739 100644 --- a/mysql-test/suite/binlog/r/binlog_row_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result @@ -1309,3 +1309,27 @@ INSERT INTO test.t1 VALUES (1), (2); CREATE TABLE test.t2 SELECT * FROM test.t1; USE test; DROP TABLES t1, t2; +RESET MASTER; +CREATE TABLE t1 (a INT PRIMARY KEY); +BINLOG ' +3u9kSA8KAAAAZgAAAGoAAAABAAQANS4xLjM1LW1hcmlhLWJldGExLWRlYnVnLWxvZwAAAAAAAAAA +AAAAAAAAAAAAAAAAAADe72RIEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC +'; +INSERT INTO t1 VALUES (1); +BINLOG ' +3u9kSBMUAAAAKQAAAJEBAAAAABoAAAAAAAAABHRlc3QAAnQxAAEDAAA= +3u9kSBcUAAAAIgAAALMBAAAQABoAAAAAAAEAAf/+AgAAAA== +'; +SHOW BINLOG EVENTS; +Log_name Pos Event_type Server_id End_log_pos Info +# # Format_desc 1 # Server ver: #, Binlog ver: # +# # Query 1 # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) +# # Query 1 # BEGIN +# # Table_map 1 # table_id: # (test.t1) +# # Write_rows 1 # table_id: # flags: STMT_END_F +# # Query 1 # COMMIT +# # Query 1 # BEGIN +# # Table_map 1 # table_id: # (test.t1) +# # Write_rows 1 # table_id: # flags: STMT_END_F +# # Query 1 # COMMIT +DROP TABLE t1; diff --git a/mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result b/mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result index 503076d66d9..75c088e595d 100644 --- a/mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result +++ b/mysql-test/suite/binlog/r/binlog_row_drop_tmp_tbl.result @@ -1,17 +1,32 @@ -drop database if exists `drop-temp+table-test`; -reset master; -create database `drop-temp+table-test`; -use `drop-temp+table-test`; -create temporary table shortn1 (a int); -create temporary table `table:name` (a int); -create temporary table shortn2 (a int); -select get_lock("a",10); -get_lock("a",10) +DROP DATABASE IF EXISTS `drop-temp+table-test`; +RESET MASTER; +CREATE DATABASE `drop-temp+table-test`; +USE `drop-temp+table-test`; +CREATE TEMPORARY TABLE shortn1 (a INT); +CREATE TEMPORARY TABLE `table:name` (a INT); +CREATE TEMPORARY TABLE shortn2 (a INT); +CREATE TEMPORARY TABLE tmp(c1 int); +CREATE TEMPORARY TABLE tmp1(c1 int); +CREATE TEMPORARY TABLE tmp2(c1 int); +CREATE TEMPORARY TABLE tmp3(c1 int); +CREATE TABLE t(c1 int); +DROP TEMPORARY TABLE IF EXISTS tmp; +DROP TEMPORARY TABLE IF EXISTS tmp; +DROP TEMPORARY TABLE IF EXISTS tmp, tmp1; +DROP TEMPORARY TABLE tmp3; +DROP TABLE IF EXISTS tmp2, t; +DROP TABLE IF EXISTS tmp2, t; +SELECT GET_LOCK("a",10); +GET_LOCK("a",10) 1 -select get_lock("a",10); -get_lock("a",10) +USE test; +SELECT GET_LOCK("a",10); +GET_LOCK("a",10) 1 show binlog events from <binlog_start>; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # create database `drop-temp+table-test` -drop database `drop-temp+table-test`; +master-bin.000001 # Query # # CREATE DATABASE `drop-temp+table-test` +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TABLE t(c1 int) +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TABLE IF EXISTS `t` /* generated by server */ +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TABLE IF EXISTS tmp2, t +DROP DATABASE `drop-temp+table-test`; diff --git a/mysql-test/suite/binlog/r/binlog_row_failure_mixing_engines.result b/mysql-test/suite/binlog/r/binlog_row_failure_mixing_engines.result new file mode 100644 index 00000000000..45c8640d3e3 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_row_failure_mixing_engines.result @@ -0,0 +1,440 @@ +################################################################################### +# CONFIGURATION +################################################################################### +CREATE TABLE nt_1 (a text, b int PRIMARY KEY) ENGINE = MyISAM; +CREATE TABLE nt_2 (a text, b int PRIMARY KEY) ENGINE = MyISAM; +CREATE TABLE tt_1 (a text, b int PRIMARY KEY) ENGINE = Innodb; +CREATE TABLE tt_2 (a text, b int PRIMARY KEY) ENGINE = Innodb; +CREATE TRIGGER tr_i_tt_1_to_nt_1 BEFORE INSERT ON tt_1 FOR EACH ROW +BEGIN +INSERT INTO nt_1 VALUES (NEW.a, NEW.b); +END| +CREATE TRIGGER tr_i_nt_2_to_tt_2 BEFORE INSERT ON nt_2 FOR EACH ROW +BEGIN +INSERT INTO tt_2 VALUES (NEW.a, NEW.b); +END| +################################################################################### +# CHECK HISTORY IN BINLOG +################################################################################### + + + +*** "B M* T C" with error in M* generates in the binlog the "B M* R B T C" entries + +INSERT INTO nt_1 VALUES ("new text 1", 1); +BEGIN; +INSERT INTO tt_1 VALUES (USER(), 2), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 3", 3); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + +INSERT INTO tt_2 VALUES ("new text 4", 4); +BEGIN; +INSERT INTO nt_2 VALUES (USER(), 5), (USER(), 4); +ERROR 23000: Duplicate entry '4' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 6", 6); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B M M* T C" with error in M* generates in the binlog the "B M M* T C" entries + +INSERT INTO nt_1 VALUES ("new text 10", 10); +BEGIN; +INSERT INTO tt_1 VALUES ("new text 7", 7), ("new text 8", 8); +INSERT INTO tt_1 VALUES (USER(), 9), (USER(), 10); +ERROR 23000: Duplicate entry '10' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 11", 11); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + +INSERT INTO tt_2 VALUES ("new text 15", 15); +BEGIN; +INSERT INTO nt_2 VALUES ("new text 12", 12), ("new text 13", 13); +INSERT INTO nt_2 VALUES (USER(), 14), (USER(), 15); +ERROR 23000: Duplicate entry '15' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 16", 16); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B M* M* T C" with error in M* generates in the binlog the "B M* R B M* R B T C" entries + +INSERT INTO nt_1 VALUES ("new text 18", 18); +INSERT INTO nt_1 VALUES ("new text 20", 20); +BEGIN; +INSERT INTO tt_1 VALUES (USER(), 17), (USER(), 18); +ERROR 23000: Duplicate entry '18' for key 'PRIMARY' +INSERT INTO tt_1 VALUES (USER(), 19), (USER(), 20); +ERROR 23000: Duplicate entry '20' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 21", 21); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_1) +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + +INSERT INTO tt_2 VALUES ("new text 23", 23); +INSERT INTO tt_2 VALUES ("new text 25", 25); +BEGIN; +INSERT INTO nt_2 VALUES (USER(), 22), (USER(), 23); +ERROR 23000: Duplicate entry '23' for key 'PRIMARY' +INSERT INTO nt_2 VALUES (USER(), 24), (USER(), 25); +ERROR 23000: Duplicate entry '25' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 26", 26); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B T INSERT M...SELECT* C" with an error in INSERT M...SELECT* generates +*** in the binlog the following entries: "Nothing". +*** There is a bug in that will be fixed after WL#2687. Please, check BUG#47175 for further details. + +TRUNCATE TABLE nt_2; +TRUNCATE TABLE tt_2; +INSERT INTO tt_2 VALUES ("new text 7", 7); +BEGIN; +INSERT INTO tt_2 VALUES ("new text 27", 27); +INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; +ERROR 23000: Duplicate entry '7' for key 'PRIMARY' +INSERT INTO tt_2 VALUES ("new text 28", 28); +ROLLBACK; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE nt_2 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE tt_2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B INSERT M..SELECT* C" with an error in INSERT M...SELECT* generates +*** in the binlog the following entries: "B INSERT M..SELECT* R". + +TRUNCATE TABLE nt_2; +TRUNCATE TABLE tt_2; +INSERT INTO tt_2 VALUES ("new text 7", 7); +BEGIN; +INSERT INTO nt_2(a, b) SELECT USER(), b FROM nt_1; +ERROR 23000: Duplicate entry '7' for key 'PRIMARY' +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE nt_2 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE tt_2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_2) +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK + + + +*** "B N N T C" generates in the binlog the "B N C B N C B T C" entries + +TRUNCATE TABLE nt_1; +TRUNCATE TABLE tt_2; +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 1); +INSERT INTO nt_1 VALUES (USER(), 2); +INSERT INTO tt_2 VALUES (USER(), 3); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE nt_1 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; TRUNCATE TABLE tt_2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B N N T R" generates in the binlog the "B N C B N C B T R" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 4); +INSERT INTO nt_1 VALUES (USER(), 5); +INSERT INTO tt_2 VALUES (USER(), 6); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK + + + +*** "B N* N* T C" with error in N* generates in the binlog the "B N R B N R B T C" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 7), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO nt_1 VALUES (USER(), 8), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO tt_2 VALUES (USER(), 9); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B N* N* T R" with error in N* generates in the binlog the "B N R B N R B T R" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 10), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO nt_1 VALUES (USER(), 11), (USER(), 1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +INSERT INTO tt_2 VALUES (USER(), 12); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK + + + +*** "B N N T N T C" generates in the binlog the "B N C B N C B T N T C" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 13); +INSERT INTO nt_1 VALUES (USER(), 14); +INSERT INTO tt_2 VALUES (USER(), 15); +INSERT INTO nt_1 VALUES (USER(), 16); +INSERT INTO tt_2 VALUES (USER(), 17); +COMMIT; +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ + + + +*** "B N N T N T R" generates in the binlog the "B N C B N C B T N T R" entries + +BEGIN; +INSERT INTO nt_1 VALUES (USER(), 18); +INSERT INTO nt_1 VALUES (USER(), 19); +INSERT INTO tt_2 VALUES (USER(), 20); +INSERT INTO nt_1 VALUES (USER(), 21); +INSERT INTO tt_2 VALUES (USER(), 22); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.nt_1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.tt_2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +################################################################################### +# CLEAN +################################################################################### +DROP TABLE tt_1; +DROP TABLE tt_2; +DROP TABLE nt_1; +DROP TABLE nt_2; diff --git a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result index 9ae5121f618..4ccc3b5e797 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result @@ -133,6 +133,10 @@ master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT insert into t1 values(11); commit; show binlog events from <binlog_start>; @@ -144,6 +148,8 @@ master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t2) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ @@ -272,6 +278,10 @@ master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; drop table t1,t2 master-bin.000001 # Query # # use `test`; create table t0 (n int) master-bin.000001 # Query # # BEGIN @@ -372,7 +382,7 @@ master-bin.000001 # Query # # use `test`; DROP TABLE if exists t2 master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t2 master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a int, b int, primary key (a)) engine=innodb master-bin.000001 # Query # # BEGIN @@ -390,9 +400,11 @@ master-bin.000001 # Query # # use `test`; DROP TABLE t2 master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F @@ -400,7 +412,7 @@ master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; TRUNCATE table t2 master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) @@ -917,7 +929,7 @@ master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci -master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a, @b) SET b=((@b) + `bug27417`(2)) ;file_id=# master-bin.000001 # Query # # ROLLBACK drop trigger trg_del_t2; drop table t1,t2,t3,t4,t5; diff --git a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result new file mode 100644 index 00000000000..2687b21213a --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result @@ -0,0 +1,161 @@ +Verbose statements from : write-partial-row.binlog +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +stmt +### INSERT INTO mysql.ndb_apply_status +### SET +### @1=1 +### @2=25769803786 +### @3='' +### @4=0 +### @5=0 +### INSERT INTO test.ba +### SET +### @1=3 +### @2=3 +### @3=3 +### INSERT INTO test.ba +### SET +### @1=1 +### @2=1 +### @3=1 +### INSERT INTO test.ba +### SET +### @1=2 +### @2=2 +### @3=2 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=4 +### INSERT INTO test.ba +### SET +### @1=4 +### @3=40 +### DELETE FROM test.ba +### WHERE +### @1=2 +drop table raw_binlog_rows; +Verbose statements from : write-full-row.binlog +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +stmt +### INSERT INTO mysql.ndb_apply_status +### SET +### @1=2 +### @2=25769803786 +### @3='' +### @4=0 +### @5=0 +### INSERT INTO test.ba +### SET +### @1=3 +### @2=3 +### @3=3 +### INSERT INTO test.ba +### SET +### @1=1 +### @2=1 +### @3=1 +### INSERT INTO test.ba +### SET +### @1=2 +### @2=2 +### @3=2 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=4 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=40 +### DELETE FROM test.ba +### WHERE +### @1=2 +drop table raw_binlog_rows; +Verbose statements from : update-partial-row.binlog +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +stmt +### INSERT INTO mysql.ndb_apply_status +### SET +### @1=3 +### @2=25769803786 +### @3='' +### @4=0 +### @5=0 +### INSERT INTO test.ba +### SET +### @1=3 +### @2=3 +### @3=3 +### INSERT INTO test.ba +### SET +### @1=1 +### @2=1 +### @3=1 +### INSERT INTO test.ba +### SET +### @1=2 +### @2=2 +### @3=2 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=4 +### UPDATE test.ba +### WHERE +### @1=4 +### @3=4 +### SET +### @1=4 +### @3=40 +### DELETE FROM test.ba +### WHERE +### @1=2 +drop table raw_binlog_rows; +Verbose statements from : update-full-row.binlog +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +stmt +### INSERT INTO mysql.ndb_apply_status +### SET +### @1=4 +### @2=25769803786 +### @3='' +### @4=0 +### @5=0 +### INSERT INTO test.ba +### SET +### @1=3 +### @2=3 +### @3=3 +### INSERT INTO test.ba +### SET +### @1=1 +### @2=1 +### @3=1 +### INSERT INTO test.ba +### SET +### @1=2 +### @2=2 +### @3=2 +### INSERT INTO test.ba +### SET +### @1=4 +### @2=4 +### @3=4 +### UPDATE test.ba +### WHERE +### @1=4 +### @2=4 +### @3=4 +### SET +### @1=4 +### @2=4 +### @3=40 +### DELETE FROM test.ba +### WHERE +### @1=2 +drop table raw_binlog_rows; diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result index d05d3ccdb7a..eebcfceaa25 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result +++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result @@ -784,3 +784,24 @@ INSERT INTO test.t1 VALUES (1), (2); CREATE TABLE test.t2 SELECT * FROM test.t1; USE test; DROP TABLES t1, t2; +RESET MASTER; +CREATE TABLE t1 (a INT PRIMARY KEY); +BINLOG ' +3u9kSA8KAAAAZgAAAGoAAAABAAQANS4xLjM1LW1hcmlhLWJldGExLWRlYnVnLWxvZwAAAAAAAAAA +AAAAAAAAAAAAAAAAAADe72RIEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC +'; +INSERT INTO t1 VALUES (1); +BINLOG ' +3u9kSBMUAAAAKQAAAJEBAAAAABoAAAAAAAAABHRlc3QAAnQxAAEDAAA= +3u9kSBcUAAAAIgAAALMBAAAQABoAAAAAAAEAAf/+AgAAAA== +'; +SHOW BINLOG EVENTS; +Log_name Pos Event_type Server_id End_log_pos Info +# # Format_desc 1 # Server ver: #, Binlog ver: # +# # Query 1 # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) +# # Query 1 # use `test`; INSERT INTO t1 VALUES (1) +# # Query 1 # BEGIN +# # Table_map 1 # table_id: # (test.t1) +# # Write_rows 1 # table_id: # flags: STMT_END_F +# # Query 1 # COMMIT +DROP TABLE t1; diff --git a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result index f3a01f66fc2..434c1b0896f 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result +++ b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result @@ -127,7 +127,7 @@ master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; create table t2 (a varchar(200)) engine=blackhole master-bin.000001 # Query # # BEGIN master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=581 -master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/words.dat' into table t2 ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE `t2` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a) ;file_id=# master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # use `test`; alter table t1 add b int master-bin.000001 # Query # # use `test`; alter table t1 drop b diff --git a/mysql-test/suite/binlog/r/binlog_stm_do_db.result b/mysql-test/suite/binlog/r/binlog_stm_do_db.result new file mode 100644 index 00000000000..ab4ba7cdca1 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_stm_do_db.result @@ -0,0 +1,42 @@ +SET @old_isolation_level= @@session.tx_isolation; +SET @@session.tx_isolation= 'READ-COMMITTED'; +CREATE DATABASE b42829; +use b42829; +CREATE TABLE t1 (x int, y int) engine=InnoDB; +CREATE TABLE t2 (x int, y int) engine=InnoDB; +CREATE DATABASE b42829_filtered; +use b42829_filtered; +CREATE TABLE t1 (x int, y int) engine=InnoDB; +CREATE TABLE t2 (x int, y int) engine=InnoDB; +SET @@session.sql_log_bin= 0; +INSERT INTO b42829_filtered.t1 VALUES (100,100); +INSERT INTO b42829.t1 VALUES (100,100); +SET @@session.sql_log_bin= 1; +### assertion: the inserts will not raise log error because +### binlog-do-db is filtering used database +INSERT INTO t2 VALUES (1,2), (1,3), (1,4); +INSERT INTO t1 SELECT * FROM t2; +### assertion: assert that despite updating a not filtered +### database this wont trigger an error as the +### used database is the filtered one. +UPDATE b42829_filtered.t1 ft1, b42829.t1 nft1 SET ft1.x=1, nft1.x=2; +use b42829; +### assertion: the statements *will* raise log error because +### binlog-do-db is not filtering used database +BEGIN; +INSERT INTO t2 VALUES (1,2), (1,3), (1,4); +ERROR HY000: Binary logging not possible. Message: Transaction level 'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT' +UPDATE b42829_filtered.t1 ft1, b42829.t1 nft1 SET ft1.x=1, nft1.x=2; +ERROR HY000: Binary logging not possible. Message: Transaction level 'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT' +INSERT INTO t1 SELECT * FROM t2; +ERROR HY000: Binary logging not possible. Message: Transaction level 'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT' +COMMIT; +### assertion: filtered events did not make into the binlog +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # CREATE DATABASE b42829 +master-bin.000001 # Query # # use `b42829`; CREATE TABLE t1 (x int, y int) engine=InnoDB +master-bin.000001 # Query # # use `b42829`; CREATE TABLE t2 (x int, y int) engine=InnoDB +DROP DATABASE b42829; +DROP DATABASE b42829_filtered; +SET @@session.tx_isolation= @old_isolation_level; diff --git a/mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result b/mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result index 4d24b2409b9..19ddcf49080 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result +++ b/mysql-test/suite/binlog/r/binlog_stm_drop_tmp_tbl.result @@ -1,21 +1,44 @@ -drop database if exists `drop-temp+table-test`; -reset master; -create database `drop-temp+table-test`; -use `drop-temp+table-test`; -create temporary table shortn1 (a int); -create temporary table `table:name` (a int); -create temporary table shortn2 (a int); -select get_lock("a",10); -get_lock("a",10) +DROP DATABASE IF EXISTS `drop-temp+table-test`; +RESET MASTER; +CREATE DATABASE `drop-temp+table-test`; +USE `drop-temp+table-test`; +CREATE TEMPORARY TABLE shortn1 (a INT); +CREATE TEMPORARY TABLE `table:name` (a INT); +CREATE TEMPORARY TABLE shortn2 (a INT); +CREATE TEMPORARY TABLE tmp(c1 int); +CREATE TEMPORARY TABLE tmp1(c1 int); +CREATE TEMPORARY TABLE tmp2(c1 int); +CREATE TEMPORARY TABLE tmp3(c1 int); +CREATE TABLE t(c1 int); +DROP TEMPORARY TABLE IF EXISTS tmp; +DROP TEMPORARY TABLE IF EXISTS tmp; +DROP TEMPORARY TABLE IF EXISTS tmp, tmp1; +DROP TEMPORARY TABLE tmp3; +DROP TABLE IF EXISTS tmp2, t; +DROP TABLE IF EXISTS tmp2, t; +SELECT GET_LOCK("a",10); +GET_LOCK("a",10) 1 -select get_lock("a",10); -get_lock("a",10) +USE test; +SELECT GET_LOCK("a",10); +GET_LOCK("a",10) 1 show binlog events from <binlog_start>; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # create database `drop-temp+table-test` -master-bin.000001 # Query # # use `drop-temp+table-test`; create temporary table shortn1 (a int) -master-bin.000001 # Query # # use `drop-temp+table-test`; create temporary table `table:name` (a int) -master-bin.000001 # Query # # use `drop-temp+table-test`; create temporary table shortn2 (a int) +master-bin.000001 # Query # # CREATE DATABASE `drop-temp+table-test` +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE shortn1 (a INT) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE `table:name` (a INT) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE shortn2 (a INT) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE tmp(c1 int) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE tmp1(c1 int) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE tmp2(c1 int) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TEMPORARY TABLE tmp3(c1 int) +master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TABLE t(c1 int) +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TEMPORARY TABLE IF EXISTS tmp +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TEMPORARY TABLE IF EXISTS tmp +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TEMPORARY TABLE IF EXISTS tmp, tmp1 +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TEMPORARY TABLE tmp3 +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TABLE IF EXISTS tmp2, t +master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TABLE IF EXISTS tmp2, t master-bin.000001 # Query # # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `shortn2`,`table:name`,`shortn1` -drop database `drop-temp+table-test`; +DROP DATABASE `drop-temp+table-test`; diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index c15374dc1c6..06c57fba2e7 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -625,7 +625,7 @@ master-bin.000001 # Query # # BEGIN master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# master-bin.000001 # Intvar # # INSERT_ID=10 -master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a, @b) SET b=((@b) + `bug27417`(2)) ;file_id=# master-bin.000001 # Query # # ROLLBACK /* the output must denote there is the query */; drop trigger trg_del_t2; @@ -863,7 +863,7 @@ master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci -master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/rpl_loaddata.dat' INTO TABLE `t4` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a, @b) SET b=((@b) + `bug27417`(2)) ;file_id=# master-bin.000001 # Query # # ROLLBACK drop trigger trg_del_t2; drop table t1,t2,t3,t4,t5; diff --git a/mysql-test/suite/binlog/std_data/update-full-row.binlog b/mysql-test/suite/binlog/std_data/update-full-row.binlog Binary files differnew file mode 100644 index 00000000000..866a351033e --- /dev/null +++ b/mysql-test/suite/binlog/std_data/update-full-row.binlog diff --git a/mysql-test/suite/binlog/std_data/update-partial-row.binlog b/mysql-test/suite/binlog/std_data/update-partial-row.binlog Binary files differnew file mode 100644 index 00000000000..67e3611aa3a --- /dev/null +++ b/mysql-test/suite/binlog/std_data/update-partial-row.binlog diff --git a/mysql-test/suite/binlog/std_data/write-full-row.binlog b/mysql-test/suite/binlog/std_data/write-full-row.binlog Binary files differnew file mode 100644 index 00000000000..b9edb89e91a --- /dev/null +++ b/mysql-test/suite/binlog/std_data/write-full-row.binlog diff --git a/mysql-test/suite/binlog/std_data/write-partial-row.binlog b/mysql-test/suite/binlog/std_data/write-partial-row.binlog Binary files differnew file mode 100644 index 00000000000..7424ec4e940 --- /dev/null +++ b/mysql-test/suite/binlog/std_data/write-partial-row.binlog diff --git a/mysql-test/suite/binlog/t/binlog_delete_and_flush_index.test b/mysql-test/suite/binlog/t/binlog_delete_and_flush_index.test new file mode 100644 index 00000000000..84c83687486 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_delete_and_flush_index.test @@ -0,0 +1,114 @@ +# BUG#34582: FLUSH LOGS does not close and reopen the binlog index +# file +# +# WHAT +# ==== +# +# We want to test that FLUSH LOGS closes and reopens binlog index +# file. +# +# HOW +# === +# +# PREPARE: +# 1. create some binlog events +# 2. show index content, binlog events and binlog contents +# for mysql-bin.000001 +# 3. copy the mysql-bin.000001 to mysql-bin-b34582.000001 +# 4. change the index file so that mysql-bin.000001 is replaced +# with mysql-bin-b34582.000001 +# 5. FLUSH the logs so that new index is closed and reopened +# +# ASSERTIONS: +# 1. index file contents shows mysql-bin-b34582.000001 and +# mysql-bin.000002 +# 1. show binary logs shows current index entries +# 2. binlog contents for mysql-bin-b34582.000001 are displayed +# 3. Purge binlogs up to the latest one succeeds +# 4. SHOW BINARY LOGS presents the latest one only after purging +# 5. Purged binlogs files don't exist in the filesystem +# 6. Not purged binlog file exists in the filesystem +# +# CLEAN UP: +# 1. RESET MASTER +# + +-- source include/have_log_bin.inc + +RESET MASTER; + +-- let $datadir= `SELECT @@datadir` +-- let $index=$datadir/master-bin.index +-- chmod 0644 $index + +# action: issue one command so that binlog gets some event +CREATE TABLE t1 (a int); + +-- echo ### assertion: index file contains regular entries +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval SET @index=LOAD_FILE('$index') +-- replace_regex /\.[\\\/]master/master/ +SELECT @index; + +--echo ### assertion: show original binlogs +-- source include/show_binary_logs.inc + +--echo ### assertion: binlog contents from regular entries +-- source include/show_binlog_events.inc + +# action: copy binlogs to other names and change entries in index file +-- copy_file $datadir/master-bin.000001 $datadir/master-bin-b34582.000001 +let INDEX_FILE=$index; +perl; +$file= $ENV{'INDEX_FILE'}; +open(FILE, ">$file") || die "Unable to open $file."; +truncate(FILE,0); +close ($file); +EOF + +-- append_file $index +master-bin-b34582.000001 +EOF + +# action: should cause rotation, and creation of new binlogs +FLUSH LOGS; + +# file is not used anymore - remove it (mysql closed on flush logs). +-- remove_file $datadir/master-bin.000001 + +-- echo ### assertion: index file contains renamed binlog and the new one +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval SET @index=LOAD_FILE('$index') +-- replace_regex /\.[\\\/]master/master/ +SELECT @index; + +-- echo ### assertion: original binlog content still exists, despite we +-- echo ### renamed and changed the index file +-- source include/show_binlog_events.inc + +-- echo ### assertion: user changed binlog index shows correct entries +-- source include/show_binary_logs.inc + +DROP TABLE t1; + +-- echo ### assertion: purging binlogs up to binlog created after instrumenting index file should work +-- let $current_binlog= query_get_value(SHOW MASTER STATUS, File, 1) +-- eval PURGE BINARY LOGS TO '$current_binlog' + +-- echo ### assertion: show binary logs should only contain latest binlog +-- source include/show_binary_logs.inc + +-- echo ### assertion: assert that binlog files were indeed purged (using file_exists calls) +-- error 1 +-- file_exists $datadir/master-bin-b34852.000001 + +-- echo ### assertion: assert that not purged binlog file exists +-- file_exists $datadir/$current_binlog + +-- echo ### assertion: show index file contents and these should match show binary logs issued above +-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +-- eval SET @index=LOAD_FILE('$index') +-- replace_regex /\.[\\\/]master/master/ +SELECT @index; + +RESET MASTER; diff --git a/mysql-test/suite/binlog/t/binlog_mixed_failure_mixing_engines.test b/mysql-test/suite/binlog/t/binlog_mixed_failure_mixing_engines.test new file mode 100644 index 00000000000..09b168c2882 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_mixed_failure_mixing_engines.test @@ -0,0 +1,4 @@ +--source include/have_binlog_format_mixed.inc +--source include/have_innodb.inc + +--source extra/binlog_tests/binlog_failure_mixing_engines.test diff --git a/mysql-test/suite/binlog/t/binlog_row_failure_mixing_engines.test b/mysql-test/suite/binlog/t/binlog_row_failure_mixing_engines.test new file mode 100644 index 00000000000..e25af7a7e10 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_row_failure_mixing_engines.test @@ -0,0 +1,4 @@ +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc + +--source extra/binlog_tests/binlog_failure_mixing_engines.test diff --git a/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test b/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test index 0422c204270..6682d84d9c9 100644 --- a/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test +++ b/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test @@ -112,17 +112,22 @@ while($i) # remove unecessary files -- remove_file $outfile.1 -- remove_file $outfile.2 - + + # + # The two tests are canceled since we introduced the patch of bug#46998, + # which will make mydsqlbinlog output the 'BEGIN', 'COMMIT' and 'ROLLBACK' + # in regardless of database filtering + # # assertion: events for database test are filtered - if (`SELECT INSTR(@b42941_output.1, 'test')`) - { - -- echo **** ERROR **** Database name 'test' FOUND in mysqlbinlog output ($flags $outfile.1). - } - - if (`SELECT INSTR(@b42941_output.2, 'test')`) - { - -- echo **** ERROR **** Database name 'test' FOUND in mysqlbinlog output ($flags $outfile.2). - } + #if (`SELECT INSTR(@b42941_output.1, 'test')`) + #{ + #-- echo **** ERROR **** Database name 'test' FOUND in mysqlbinlog output ($flags $outfile.1). + #} + + #if (`SELECT INSTR(@b42941_output.2, 'test')`) + #{ + #-- echo **** ERROR **** Database name 'test' FOUND in mysqlbinlog output ($flags $outfile.2). + #} # assertion: events for database b42941 are not filtered if (!`SELECT INSTR(@b42941_output.1, 'b42941')`) diff --git a/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test b/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test new file mode 100644 index 00000000000..42d92e1a44d --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test @@ -0,0 +1,86 @@ +######################################################## +# Test mysqlbinlog command with Ndb produced Binlog +# variants +# +# WHAT +# ==== +# This test aims to check that the mysqlbinlog --verbose +# command can output binlogs in 4 format variants, currently +# used by Ndb +# +# 1) Updates logged as write_row events +# Only primary key and updated columns included in the +# event +# 2) Updates logged as write_row_events +# All columns included in the event +# 3) Updates logged as update_row events +# Only primary key and updated columns included in the +# event +# 4) Updates logged as update_row events +# All columns included in the event +# +# Format variant (1) is the Ndb default. +# Bug#47323 resulted in binlogs generated in format (1) +# being incorrectly parsed by the mysqlbinlog --verbose +# option +# +# HOW +# === +# Row-based binlog files in each format have been +# captured from an Ndb cluster +# These are output using the mysqlbinlog --verbose +# tool and the output is checked. +# +######################################################## + +# We require binlog_format_row as we're independent of binlog format +# and there's no point running the same test 3 times +-- source include/have_binlog_format_row.inc + +--disable_query_log +--let $binlog_file=write-partial-row.binlog +--exec $MYSQL_BINLOG --verbose suite/binlog/std_data/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +create table raw_binlog_rows (txt varchar(1000)); +--eval load data local infile '$MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql' into table raw_binlog_rows columns terminated by '\n'; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +--enable_query_log +--echo Verbose statements from : $binlog_file +# Output --verbose lines, with extra Windows CR's trimmed +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +drop table raw_binlog_rows; + +--disable_query_log +--let $binlog_file=write-full-row.binlog +--exec $MYSQL_BINLOG --verbose suite/binlog/std_data/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +create table raw_binlog_rows (txt varchar(1000)); +--eval load data local infile '$MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql' into table raw_binlog_rows columns terminated by '\n'; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +--enable_query_log +--echo Verbose statements from : $binlog_file +# Output --verbose lines, with extra Windows CR's trimmed +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +drop table raw_binlog_rows; + +--disable_query_log +--let $binlog_file=update-partial-row.binlog +--exec $MYSQL_BINLOG --verbose suite/binlog/std_data/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +create table raw_binlog_rows (txt varchar(1000)); +--eval load data local infile '$MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql' into table raw_binlog_rows columns terminated by '\n'; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +--enable_query_log +--echo Verbose statements from : $binlog_file +# Output --verbose lines, with extra Windows CR's trimmed +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +drop table raw_binlog_rows; + +--disable_query_log +--let $binlog_file=update-full-row.binlog +--exec $MYSQL_BINLOG --verbose suite/binlog/std_data/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +create table raw_binlog_rows (txt varchar(1000)); +--eval load data local infile '$MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql' into table raw_binlog_rows columns terminated by '\n'; +--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_verbose.sql +--enable_query_log +--echo Verbose statements from : $binlog_file +# Output --verbose lines, with extra Windows CR's trimmed +select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%'; +drop table raw_binlog_rows; diff --git a/mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt b/mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt new file mode 100644 index 00000000000..e2cfcb299cf --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt @@ -0,0 +1 @@ +--binlog-do-db=b42829 diff --git a/mysql-test/suite/binlog/t/binlog_stm_do_db.test b/mysql-test/suite/binlog/t/binlog_stm_do_db.test new file mode 100644 index 00000000000..858bc8cc683 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_stm_do_db.test @@ -0,0 +1,90 @@ +# BUG#42829: binlogging enabled for all schemas regardless of +# binlog-db-db / binlog-ignore-db +# +# WHAT +# ==== +# +# We want to test whether filtered events from binlog will cause +# raising an error mentioning that statement is unable to be logged or +# not, when: +# +# 1. isolation level READ-COMMITTED; AND +# +# 2. using InnoDB engine; AND +# +# 3. using SBL (in which case InnoDB will only allow RBL). +# +# HOW +# === +# +# The test is implemented as follows: +# +# i) set tx_isolation to read-committed. +# +# ii) create two databases (one filtered other not - using +# binlog-do-db) +# +# iii) Create statements that are to be filtered on filtered db +# +# - At this point, before fix, an error would be raised +# +# iv) do the same thing for not the filtered database and check +# that events throw an error: +# +# - Error: ER_BINLOG_STMT_MODE_AND_ROW_ENGINE +# + +-- source include/have_log_bin.inc +-- source include/have_innodb.inc +-- source include/have_binlog_format_statement.inc + +SET @old_isolation_level= @@session.tx_isolation; +SET @@session.tx_isolation= 'READ-COMMITTED'; + +-- let $engine= InnoDB +-- let $filtered= b42829_filtered +-- let $not_filtered= b42829 + +-- eval CREATE DATABASE $not_filtered +-- eval use $not_filtered +-- eval CREATE TABLE t1 (x int, y int) engine=$engine +-- eval CREATE TABLE t2 (x int, y int) engine=$engine + +-- eval CREATE DATABASE $filtered +-- eval use $filtered +-- eval CREATE TABLE t1 (x int, y int) engine=$engine +-- eval CREATE TABLE t2 (x int, y int) engine=$engine + +SET @@session.sql_log_bin= 0; +-- eval INSERT INTO $filtered.t1 VALUES (100,100) +-- eval INSERT INTO $not_filtered.t1 VALUES (100,100) +SET @@session.sql_log_bin= 1; + +-- echo ### assertion: the inserts will not raise log error because +-- echo ### binlog-do-db is filtering used database +INSERT INTO t2 VALUES (1,2), (1,3), (1,4); +INSERT INTO t1 SELECT * FROM t2; + +-- echo ### assertion: assert that despite updating a not filtered +-- echo ### database this wont trigger an error as the +-- echo ### used database is the filtered one. +-- eval UPDATE $filtered.t1 ft1, $not_filtered.t1 nft1 SET ft1.x=1, nft1.x=2 + +-- eval use $not_filtered +-- echo ### assertion: the statements *will* raise log error because +-- echo ### binlog-do-db is not filtering used database +BEGIN; +-- error ER_BINLOG_LOGGING_IMPOSSIBLE +INSERT INTO t2 VALUES (1,2), (1,3), (1,4); +-- error ER_BINLOG_LOGGING_IMPOSSIBLE +-- eval UPDATE $filtered.t1 ft1, $not_filtered.t1 nft1 SET ft1.x=1, nft1.x=2 +-- error ER_BINLOG_LOGGING_IMPOSSIBLE +INSERT INTO t1 SELECT * FROM t2; +COMMIT; + +-- echo ### assertion: filtered events did not make into the binlog +source include/show_binlog_events.inc; + +-- eval DROP DATABASE $not_filtered +-- eval DROP DATABASE $filtered +SET @@session.tx_isolation= @old_isolation_level; diff --git a/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test index a5472952f08..21c11d5a3df 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test +++ b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test @@ -94,15 +94,24 @@ DROP TABLE t1; SET GLOBAL log_warnings = @old_log_warnings; -let LOG_ERROR= `SELECT @@GLOBAL.log_error`; +let $log_error_= `SELECT @@GLOBAL.log_error`; +if(!`select LENGTH('$log_error_')`) +{ + # MySQL Server on windows is started with --console and thus + # does not know the location of its .err log, use default location + let $log_error_ = $MYSQLTEST_VARDIR/log/mysqld.1.err; +} +# Assign env variable LOG_ERROR +let LOG_ERROR=$log_error_; --echo # Count the number of times the "Unsafe" message was printed --echo # to the error log. perl; - $log_error= $ENV{'LOG_ERROR'}; + use strict; + my $log_error= $ENV{'LOG_ERROR'} or die "LOG_ERROR not set"; open(FILE, "$log_error") or die("Unable to open $log_error: $!\n"); - $count = () = grep(/Bug#46265/g,<FILE>); + my $count = () = grep(/Bug#46265/g,<FILE>); print "Occurrences: $count\n"; close(FILE); EOF diff --git a/mysql-test/suite/federated/federated_debug-master.opt b/mysql-test/suite/federated/federated_debug-master.opt new file mode 100644 index 00000000000..ad9ba4795af --- /dev/null +++ b/mysql-test/suite/federated/federated_debug-master.opt @@ -0,0 +1 @@ +--loose-debug=d,simulate_detached_thread_refresh diff --git a/mysql-test/suite/federated/federated_debug.result b/mysql-test/suite/federated/federated_debug.result new file mode 100644 index 00000000000..73a6cac892e --- /dev/null +++ b/mysql-test/suite/federated/federated_debug.result @@ -0,0 +1,33 @@ +CREATE DATABASE federated; +CREATE DATABASE federated; +# +# Bug#47525: MySQL crashed (Federated) +# +# Switch to slave +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1); +# Switch to master +CREATE TABLE t1(a INT) ENGINE=FEDERATED +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/test/t1'; +SELECT * FROM t1; +a +1 +# Start a asynchronous reload +# Wait for tables to be closed +# Timeout in include/wait_show_condition.inc for +# show_statement : SHOW STATUS LIKE 'Open_tables' +# field : Value +# condition : = '0' +# max_run_time : 31 +# Ensure that the server didn't crash +SELECT * FROM t1; +a +1 +# Drop tables on master and slave +DROP TABLE t1; +DROP TABLE t1; +# Federated cleanup +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; +DROP TABLE IF EXISTS federated.t1; +DROP DATABASE IF EXISTS federated; diff --git a/mysql-test/suite/federated/federated_debug.test b/mysql-test/suite/federated/federated_debug.test new file mode 100644 index 00000000000..4152d2975b3 --- /dev/null +++ b/mysql-test/suite/federated/federated_debug.test @@ -0,0 +1,39 @@ +--source include/have_debug.inc +--source federated.inc + +--echo # +--echo # Bug#47525: MySQL crashed (Federated) +--echo # + +connection slave; +--echo # Switch to slave +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1); + +connection master; +--echo # Switch to master +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE t1(a INT) ENGINE=FEDERATED + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/test/t1'; + +SELECT * FROM t1; + +--echo # Start a asynchronous reload +--exec $MYSQLADMIN --no-defaults -S $MASTER_MYSOCK -P $MASTER_MYPORT -u root --password= refresh 2>&1 + +--echo # Wait for tables to be closed +let $show_statement= SHOW STATUS LIKE 'Open_tables'; +let $field= Value; +let $condition= = '0'; +--source include/wait_show_condition.inc + +--echo # Ensure that the server didn't crash +SELECT * FROM t1; +--echo # Drop tables on master and slave +DROP TABLE t1; +connection slave; +DROP TABLE t1; + +connection default; +--echo # Federated cleanup +source federated_cleanup.inc; diff --git a/mysql-test/suite/federated/my.cnf b/mysql-test/suite/federated/my.cnf index 3e84845b945..82600949712 100644 --- a/mysql-test/suite/federated/my.cnf +++ b/mysql-test/suite/federated/my.cnf @@ -9,4 +9,7 @@ log-bin= master-bin [ENV] MASTER_MYPORT= @mysqld.1.port +MASTER_MYSOCK= @mysqld.1.socket + SLAVE_MYPORT= @mysqld.2.port +SLAVE_MYSOCK= @mysqld.2.socket diff --git a/mysql-test/suite/funcs_1/r/is_columns_mysql.result b/mysql-test/suite/funcs_1/r/is_columns_mysql.result index 2f1f61c0525..98eeacdb74c 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_mysql.result +++ b/mysql-test/suite/funcs_1/r/is_columns_mysql.result @@ -130,7 +130,7 @@ NULL mysql procs_priv Db 2 NO char 64 192 NULL NULL utf8 utf8_bin char(64) PRI NULL mysql procs_priv Grantor 6 NO char 77 231 NULL NULL utf8 utf8_bin char(77) MUL select,insert,update,references NULL mysql procs_priv Host 1 NO char 60 180 NULL NULL utf8 utf8_bin char(60) PRI select,insert,update,references NULL mysql procs_priv Proc_priv 7 NO set 27 81 NULL NULL utf8 utf8_general_ci set('Execute','Alter Routine','Grant') select,insert,update,references -NULL mysql procs_priv Routine_name 4 NO char 64 192 NULL NULL utf8 utf8_bin char(64) PRI select,insert,update,references +NULL mysql procs_priv Routine_name 4 NO char 64 192 NULL NULL utf8 utf8_general_ci char(64) PRI select,insert,update,references NULL mysql procs_priv Routine_type 5 NULL NO enum 9 27 NULL NULL utf8 utf8_bin enum('FUNCTION','PROCEDURE') PRI select,insert,update,references NULL mysql procs_priv Timestamp 8 CURRENT_TIMESTAMP NO timestamp NULL NULL NULL NULL NULL NULL timestamp on update CURRENT_TIMESTAMP select,insert,update,references NULL mysql procs_priv User 3 NO char 16 48 NULL NULL utf8 utf8_bin char(16) PRI select,insert,update,references @@ -411,7 +411,7 @@ NULL mysql proc modified timestamp NULL NULL NULL NULL timestamp 3.0000 mysql procs_priv Host char 60 180 utf8 utf8_bin char(60) 3.0000 mysql procs_priv Db char 64 192 utf8 utf8_bin char(64) 3.0000 mysql procs_priv User char 16 48 utf8 utf8_bin char(16) -3.0000 mysql procs_priv Routine_name char 64 192 utf8 utf8_bin char(64) +3.0000 mysql procs_priv Routine_name char 64 192 utf8 utf8_general_ci char(64) 3.0000 mysql procs_priv Routine_type enum 9 27 utf8 utf8_bin enum('FUNCTION','PROCEDURE') 3.0000 mysql procs_priv Grantor char 77 231 utf8 utf8_bin char(77) 3.0000 mysql procs_priv Proc_priv set 27 81 utf8 utf8_general_ci set('Execute','Alter Routine','Grant') diff --git a/mysql-test/suite/funcs_1/r/is_statistics.result b/mysql-test/suite/funcs_1/r/is_statistics.result index 989fd9dc4e6..8452536d4ed 100644 --- a/mysql-test/suite/funcs_1/r/is_statistics.result +++ b/mysql-test/suite/funcs_1/r/is_statistics.result @@ -166,8 +166,8 @@ NULL db_datadict_2 t4 0 db_datadict_2 PRIMARY 1 f1 NULL 0 NULL NULL HASH SHOW GRANTS FOR 'testuser1'@'localhost'; Grants for testuser1@localhost GRANT USAGE ON *.* TO 'testuser1'@'localhost' -GRANT SELECT (f5, f1) ON `db_datadict_2`.`t3` TO 'testuser1'@'localhost' GRANT SELECT ON `db_datadict`.`t1` TO 'testuser1'@'localhost' WITH GRANT OPTION +GRANT SELECT (f5, f1) ON `db_datadict_2`.`t3` TO 'testuser1'@'localhost' SHOW GRANTS FOR 'testuser2'@'localhost'; Grants for testuser2@localhost GRANT USAGE ON *.* TO 'testuser2'@'localhost' @@ -185,8 +185,8 @@ NULL db_datadict_2 t3 0 db_datadict_2 PRIMARY 1 f1 NULL 0 NULL NULL HASH SHOW GRANTS FOR 'testuser1'@'localhost'; Grants for testuser1@localhost GRANT USAGE ON *.* TO 'testuser1'@'localhost' -GRANT SELECT (f5, f1) ON `db_datadict_2`.`t3` TO 'testuser1'@'localhost' GRANT SELECT ON `db_datadict`.`t1` TO 'testuser1'@'localhost' WITH GRANT OPTION +GRANT SELECT (f5, f1) ON `db_datadict_2`.`t3` TO 'testuser1'@'localhost' SHOW GRANTS FOR 'testuser2'@'localhost'; ERROR 42000: Access denied for user 'testuser1'@'localhost' to database 'mysql' # Switch to connection testuser2 diff --git a/mysql-test/suite/innodb/r/innodb-consistent.result b/mysql-test/suite/innodb/r/innodb-consistent.result new file mode 100644 index 00000000000..9115791b99c --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb-consistent.result @@ -0,0 +1,35 @@ +drop table if exists t1; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +create table t2 like t1; +insert into t2 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; +begin; +replace into t1 select * from t2; +set session transaction isolation level read committed; +set autocommit=0; +delete from t2 where a=5; +commit; +delete from t2; +commit; +commit; +begin; +insert into t1 select * from t2; +set session transaction isolation level read committed; +set autocommit=0; +delete from t2 where a=5; +commit; +delete from t2; +commit; +commit; +select * from t1; +a +1 +2 +3 +4 +5 +6 +7 +drop table t1; +drop table t2; diff --git a/mysql-test/suite/innodb/r/innodb-zip.result b/mysql-test/suite/innodb/r/innodb-zip.result index c81401743a5..21396d81ba8 100644 --- a/mysql-test/suite/innodb/r/innodb-zip.result +++ b/mysql-test/suite/innodb/r/innodb-zip.result @@ -141,7 +141,7 @@ drop table t1; CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439))) +CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); DROP TABLE t1; @@ -196,15 +196,15 @@ drop table t1; set innodb_strict_mode = on; create table t1 (id int primary key) engine = innodb key_block_size = 0; ERROR HY000: Can't create table 'test.t1' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 0. Valid values are [1, 2, 4, 8, 16] +Warning 1478 InnoDB: invalid KEY_BLOCK_SIZE = 0. Valid values are [1, 2, 4, 8, 16] Error 1005 Can't create table 'test.t1' (errno: 1478) create table t2 (id int primary key) engine = innodb key_block_size = 9; ERROR HY000: Can't create table 'test.t2' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] +Warning 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] Error 1005 Can't create table 'test.t2' (errno: 1478) create table t3 (id int primary key) engine = innodb key_block_size = 1; create table t4 (id int primary key) engine = innodb key_block_size = 2; @@ -233,30 +233,30 @@ key_block_size = 8 row_format = compressed; create table t2 (id int primary key) engine = innodb key_block_size = 8 row_format = redundant; ERROR HY000: Can't create table 'test.t2' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. +Warning 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t2' (errno: 1478) create table t3 (id int primary key) engine = innodb key_block_size = 8 row_format = compact; ERROR HY000: Can't create table 'test.t3' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. +Warning 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t3' (errno: 1478) create table t4 (id int primary key) engine = innodb key_block_size = 8 row_format = dynamic; ERROR HY000: Can't create table 'test.t4' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. +Warning 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t4' (errno: 1478) create table t5 (id int primary key) engine = innodb key_block_size = 8 row_format = default; ERROR HY000: Can't create table 'test.t5' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. +Warning 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t5' (errno: 1478) SELECT table_schema, table_name, row_format FROM information_schema.tables WHERE engine='innodb'; @@ -266,26 +266,26 @@ drop table t1; create table t1 (id int primary key) engine = innodb key_block_size = 9 row_format = redundant; ERROR HY000: Can't create table 'test.t1' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] -Error 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. +Warning 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] +Warning 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t1' (errno: 1478) create table t2 (id int primary key) engine = innodb key_block_size = 9 row_format = compact; ERROR HY000: Can't create table 'test.t2' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] -Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. +Warning 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] +Warning 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t2' (errno: 1478) create table t2 (id int primary key) engine = innodb key_block_size = 9 row_format = dynamic; ERROR HY000: Can't create table 'test.t2' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] -Error 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. +Warning 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] +Warning 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t2' (errno: 1478) SELECT table_schema, table_name, row_format FROM information_schema.tables WHERE engine='innodb'; @@ -293,45 +293,45 @@ table_schema table_name row_format set global innodb_file_per_table = off; create table t1 (id int primary key) engine = innodb key_block_size = 1; ERROR HY000: Can't create table 'test.t1' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. Error 1005 Can't create table 'test.t1' (errno: 1478) create table t2 (id int primary key) engine = innodb key_block_size = 2; ERROR HY000: Can't create table 'test.t2' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. Error 1005 Can't create table 'test.t2' (errno: 1478) create table t3 (id int primary key) engine = innodb key_block_size = 4; ERROR HY000: Can't create table 'test.t3' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. Error 1005 Can't create table 'test.t3' (errno: 1478) create table t4 (id int primary key) engine = innodb key_block_size = 8; ERROR HY000: Can't create table 'test.t4' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. Error 1005 Can't create table 'test.t4' (errno: 1478) create table t5 (id int primary key) engine = innodb key_block_size = 16; ERROR HY000: Can't create table 'test.t5' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. Error 1005 Can't create table 'test.t5' (errno: 1478) create table t6 (id int primary key) engine = innodb row_format = compressed; ERROR HY000: Can't create table 'test.t6' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table. +Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table. Error 1005 Can't create table 'test.t6' (errno: 1478) create table t7 (id int primary key) engine = innodb row_format = dynamic; ERROR HY000: Can't create table 'test.t7' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. Error 1005 Can't create table 'test.t7' (errno: 1478) create table t8 (id int primary key) engine = innodb row_format = compact; create table t9 (id int primary key) engine = innodb row_format = redundant; @@ -345,45 +345,45 @@ set global innodb_file_per_table = on; set global innodb_file_format = `0`; create table t1 (id int primary key) engine = innodb key_block_size = 1; ERROR HY000: Can't create table 'test.t1' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t1' (errno: 1478) create table t2 (id int primary key) engine = innodb key_block_size = 2; ERROR HY000: Can't create table 'test.t2' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t2' (errno: 1478) create table t3 (id int primary key) engine = innodb key_block_size = 4; ERROR HY000: Can't create table 'test.t3' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t3' (errno: 1478) create table t4 (id int primary key) engine = innodb key_block_size = 8; ERROR HY000: Can't create table 'test.t4' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t4' (errno: 1478) create table t5 (id int primary key) engine = innodb key_block_size = 16; ERROR HY000: Can't create table 'test.t5' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t5' (errno: 1478) create table t6 (id int primary key) engine = innodb row_format = compressed; ERROR HY000: Can't create table 'test.t6' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope. +Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t6' (errno: 1478) create table t7 (id int primary key) engine = innodb row_format = dynamic; ERROR HY000: Can't create table 'test.t7' (errno: 1478) -show errors; +show warnings; Level Code Message -Error 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. Error 1005 Can't create table 'test.t7' (errno: 1478) create table t8 (id int primary key) engine = innodb row_format = compact; create table t9 (id int primary key) engine = innodb row_format = redundant; diff --git a/mysql-test/suite/innodb/r/innodb_bug44571.result b/mysql-test/suite/innodb/r/innodb_bug44571.result new file mode 100644 index 00000000000..36374edcb3e --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug44571.result @@ -0,0 +1,9 @@ +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +ERROR 42000: Key column 'foo' doesn't exist in table +ALTER TABLE bug44571 ADD INDEX bug44571b (bar); +ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it +CREATE INDEX bug44571b ON bug44571 (bar); +ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it +DROP TABLE bug44571; diff --git a/mysql-test/suite/innodb/r/innodb_file_format.result b/mysql-test/suite/innodb/r/innodb_file_format.result index 9cfac5f001c..fbc67ada1bb 100644 --- a/mysql-test/suite/innodb/r/innodb_file_format.result +++ b/mysql-test/suite/innodb/r/innodb_file_format.result @@ -1,3 +1,4 @@ +call mtr.add_suppression("InnoDB: invalid innodb_file_format_check value"); select @@innodb_file_format; @@innodb_file_format Antelope diff --git a/mysql-test/suite/innodb/t/innodb-consistent-master.opt b/mysql-test/suite/innodb/t/innodb-consistent-master.opt new file mode 100644 index 00000000000..e76299453d3 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb-consistent-master.opt @@ -0,0 +1 @@ +--innodb_lock_wait_timeout=2 diff --git a/mysql-test/suite/innodb/t/innodb-consistent.test b/mysql-test/suite/innodb/t/innodb-consistent.test new file mode 100644 index 00000000000..b58d0cb0e62 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb-consistent.test @@ -0,0 +1,59 @@ +-- source include/not_embedded.inc +-- source include/have_innodb.inc +-- source suite/innodb/include/have_innodb_plugin.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# REPLACE INTO ... SELECT and INSERT INTO ... SELECT should do +# a consistent read of the source table. + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +create table t2 like t1; +insert into t2 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; + +# REPLACE INTO ... SELECT case +begin; +# this should not result in any locks on t2. +replace into t1 select * from t2; + +connection b; +set session transaction isolation level read committed; +set autocommit=0; +# should not cuase a lock wait. +delete from t2 where a=5; +commit; +delete from t2; +commit; +connection a; +commit; + +# INSERT INTO ... SELECT case +begin; +# this should not result in any locks on t2. +insert into t1 select * from t2; + +connection b; +set session transaction isolation level read committed; +set autocommit=0; +# should not cuase a lock wait. +delete from t2 where a=5; +commit; +delete from t2; +commit; +connection a; +commit; + +select * from t1; +drop table t1; +drop table t2; + +connection default; +disconnect a; +disconnect b; diff --git a/mysql-test/suite/innodb/t/innodb-zip.test b/mysql-test/suite/innodb/t/innodb-zip.test index 3ee278b7c5a..c27392ac4fa 100644 --- a/mysql-test/suite/innodb/t/innodb-zip.test +++ b/mysql-test/suite/innodb/t/innodb-zip.test @@ -106,7 +106,7 @@ drop table t1; --error ER_TOO_BIG_ROWSIZE CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439))) +CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); DROP TABLE t1; @@ -175,11 +175,11 @@ set innodb_strict_mode = on; --error ER_CANT_CREATE_TABLE create table t1 (id int primary key) engine = innodb key_block_size = 0; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t2 (id int primary key) engine = innodb key_block_size = 9; -show errors; +show warnings; create table t3 (id int primary key) engine = innodb key_block_size = 1; @@ -205,22 +205,22 @@ key_block_size = 8 row_format = compressed; --error ER_CANT_CREATE_TABLE create table t2 (id int primary key) engine = innodb key_block_size = 8 row_format = redundant; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t3 (id int primary key) engine = innodb key_block_size = 8 row_format = compact; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t4 (id int primary key) engine = innodb key_block_size = 8 row_format = dynamic; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t5 (id int primary key) engine = innodb key_block_size = 8 row_format = default; -show errors; +show warnings; SELECT table_schema, table_name, row_format FROM information_schema.tables WHERE engine='innodb'; @@ -230,17 +230,17 @@ drop table t1; --error ER_CANT_CREATE_TABLE create table t1 (id int primary key) engine = innodb key_block_size = 9 row_format = redundant; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t2 (id int primary key) engine = innodb key_block_size = 9 row_format = compact; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t2 (id int primary key) engine = innodb key_block_size = 9 row_format = dynamic; -show errors; +show warnings; SELECT table_schema, table_name, row_format FROM information_schema.tables WHERE engine='innodb'; @@ -250,25 +250,25 @@ set global innodb_file_per_table = off; --error ER_CANT_CREATE_TABLE create table t1 (id int primary key) engine = innodb key_block_size = 1; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t2 (id int primary key) engine = innodb key_block_size = 2; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t3 (id int primary key) engine = innodb key_block_size = 4; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t4 (id int primary key) engine = innodb key_block_size = 8; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t5 (id int primary key) engine = innodb key_block_size = 16; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t6 (id int primary key) engine = innodb row_format = compressed; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t7 (id int primary key) engine = innodb row_format = dynamic; -show errors; +show warnings; create table t8 (id int primary key) engine = innodb row_format = compact; create table t9 (id int primary key) engine = innodb row_format = redundant; @@ -282,25 +282,25 @@ set global innodb_file_format = `0`; --error ER_CANT_CREATE_TABLE create table t1 (id int primary key) engine = innodb key_block_size = 1; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t2 (id int primary key) engine = innodb key_block_size = 2; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t3 (id int primary key) engine = innodb key_block_size = 4; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t4 (id int primary key) engine = innodb key_block_size = 8; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t5 (id int primary key) engine = innodb key_block_size = 16; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t6 (id int primary key) engine = innodb row_format = compressed; -show errors; +show warnings; --error ER_CANT_CREATE_TABLE create table t7 (id int primary key) engine = innodb row_format = dynamic; -show errors; +show warnings; create table t8 (id int primary key) engine = innodb row_format = compact; create table t9 (id int primary key) engine = innodb row_format = redundant; diff --git a/mysql-test/suite/innodb/t/innodb_bug44571.test b/mysql-test/suite/innodb/t/innodb_bug44571.test new file mode 100644 index 00000000000..43f290cde84 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug44571.test @@ -0,0 +1,18 @@ +# +# Bug#44571 InnoDB Plugin crashes on ADD INDEX +# http://bugs.mysql.com/44571 +# +-- source include/have_innodb.inc +-- source suite/innodb/include/have_innodb_plugin.inc + +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +-- error ER_KEY_COLUMN_DOES_NOT_EXITS +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +# The following will fail, because the CHANGE foo bar was +# not communicated to InnoDB. +--error ER_NOT_KEYFILE +ALTER TABLE bug44571 ADD INDEX bug44571b (bar); +--error ER_NOT_KEYFILE +CREATE INDEX bug44571b ON bug44571 (bar); +DROP TABLE bug44571; diff --git a/mysql-test/suite/innodb/t/innodb_file_format.test b/mysql-test/suite/innodb/t/innodb_file_format.test index 293e87a413e..4823254b959 100644 --- a/mysql-test/suite/innodb/t/innodb_file_format.test +++ b/mysql-test/suite/innodb/t/innodb_file_format.test @@ -1,6 +1,8 @@ -- source include/have_innodb.inc -- source suite/innodb/include/have_innodb_plugin.inc +call mtr.add_suppression("InnoDB: invalid innodb_file_format_check value"); + let $format=`select @@innodb_file_format`; let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; diff --git a/mysql-test/suite/innodb/t/innodb_information_schema.test b/mysql-test/suite/innodb/t/innodb_information_schema.test index df65139448c..599215e9ca4 100644 --- a/mysql-test/suite/innodb/t/innodb_information_schema.test +++ b/mysql-test/suite/innodb/t/innodb_information_schema.test @@ -110,14 +110,18 @@ SELECT * FROM ```t'\"_str` WHERE c1 = '3' FOR UPDATE; -- send SELECT * FROM ```t'\"_str` WHERE c1 = '4' FOR UPDATE; -# Give time to the above 2 queries to execute before continuing. -# Without this sleep it sometimes happens that the SELECT from innodb_locks -# executes before some of them, resulting in less than expected number -# of rows being selected from innodb_locks. --- sleep 0.1 - -- enable_result_log -- connection con_verify_innodb_locks +# Wait for the above queries to execute before continuing. +# Without this, it sometimes happens that the SELECT from innodb_locks +# executes before some of them, resulting in less than expected number +# of rows being selected from innodb_locks. If there is a bug and there +# are no 14 rows in innodb_locks then this test will fail with timeout. +let $count = 14; +let $table = INFORMATION_SCHEMA.INNODB_LOCKS; +-- source include/wait_until_rows_count.inc +# the above enables the query log, re-disable it +-- disable_query_log SELECT lock_mode, lock_type, lock_table, lock_index, lock_rec, lock_data FROM INFORMATION_SCHEMA.INNODB_LOCKS ORDER BY lock_data; diff --git a/mysql-test/suite/parts/inc/partition_auto_increment.inc b/mysql-test/suite/parts/inc/partition_auto_increment.inc index 6963de90c83..2c615e58ef9 100644 --- a/mysql-test/suite/parts/inc/partition_auto_increment.inc +++ b/mysql-test/suite/parts/inc/partition_auto_increment.inc @@ -623,3 +623,195 @@ SHOW CREATE TABLE t1; SELECT * FROM t1 ORDER BY c1; DROP TABLE t1; +if (!$skip_negative_auto_inc) +{ +--echo ############################################################################# +--echo # Bug #45823 - Assertion failure in file row/row0mysql.c line 1386 +--echo # Bug #43988 - AUTO_INCREMENT errors with partitioned InnoDB tables in 5.1.31 +--echo ############################################################################## + +--echo # Inserting negative autoincrement values into a partition table (partitions >= 4) + +eval CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), + c2 INT) ENGINE=$engine PARTITION BY HASH(c1) PARTITIONS 4; + +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t(c2) VALUES (40); + +SELECT * FROM t ORDER BY c1 ASC; + +DROP TABLE t; + +--echo # Reading from a partition table (partitions >= 2 ) after inserting a negative +--echo # value into the auto increment column + + +eval CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), + c2 INT) ENGINE=$engine PARTITION BY HASH(c1) PARTITIONS 2; + +INSERT INTO t VALUES (-2,-20); +INSERT INTO t(c2) VALUES (30); + +SELECT * FROM t ORDER BY c1 ASC; + +DROP TABLE t; + +--echo # Inserting negative auto increment value into a partition table (partitions >= 2) +--echo # auto increment value > 2. + +eval CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), + c2 INT) ENGINE=$engine PARTITION BY HASH(c1) PARTITIONS 2; + +INSERT INTO t VALUES (-4,-20); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t(c2) VALUES (40); + +SELECT * FROM t ORDER BY c1 ASC; + +DROP TABLE t; + +--echo # Inserting -1 into autoincrement column of a partition table (partition >= 4) + +eval CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), + c2 INT) ENGINE=$engine PARTITION BY HASH(c1) PARTITIONS 4; + +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); + +SELECT * FROM t ORDER BY c1 ASC; + +INSERT INTO t(c2) VALUES (30); + +SELECT * FROM t ORDER BY c1 ASC; + +DROP TABLE t; + +--echo # Deleting from an auto increment table after inserting negative values + +eval CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), + c2 INT) ENGINE=$engine PARTITION BY HASH(c1) PARTITIONS 4; + +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t VALUES (-3,-20); +INSERT INTO t(c2) VALUES (40); + +SELECT * FROM t ORDER BY c1 ASC; + +if (!$skip_delete) +{ +DELETE FROM t WHERE c1 > 1; +} + +SELECT * FROM t ORDER BY c1 ASC; + +DROP TABLE t; + +--echo # Inserting a positive value that exceeds maximum allowed value for an +--echo # Auto Increment column (positive maximum) + +eval CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), + c2 INT) ENGINE=$engine PARTITION BY HASH(c1) PARTITIONS 4; + +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (126,30); +INSERT INTO t VALUES (127,40); + +--error ER_DUP_ENTRY +INSERT INTO t VALUES (128,50); +--error ER_DUP_ENTRY +INSERT INTO t VALUES (129,60); + +SELECT * FROM t ORDER BY c1 ASC; + +DROP TABLE t; + +--echo # Inserting a negative value that goes below minimum allowed value for an +--echo # Auto Increment column (negative minimum) + +eval CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), + c2 INT) ENGINE=$engine PARTITION BY HASH(c1) PARTITIONS 4; + +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-127,30); +INSERT INTO t VALUES (-128,40); + +--error ER_DUP_ENTRY +INSERT INTO t VALUES (-129,50); +--error ER_DUP_ENTRY +INSERT INTO t VALUES (-130,60); + +SELECT * FROM t ORDER BY c1 ASC; + +DROP TABLE t; + +--echo # Updating the partition table with a negative Auto Increment value + +eval CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), + c2 INT) ENGINE=$engine PARTITION BY HASH(c1) PARTITIONS 4; + +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); + +SELECT * FROM t ORDER BY c1 ASC; + +if (!$skip_update) +{ +UPDATE t SET c1 = -6 WHERE c1 = 2; +} + +SELECT * FROM t ORDER BY c1 ASC; + +INSERT INTO t(c2) VALUES (40); +INSERT INTO t(c2) VALUES (50); + +if (!$skip_update) +{ +UPDATE t SET c1 = -6 WHERE c1 = 2; +} + +SELECT * FROM t ORDER BY c1 ASC; + +DROP TABLE t; + +--echo # Updating the partition table with a value that crosses the upper limits +--echo # on both the positive and the negative side. + +eval CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), + c2 INT) ENGINE=$engine PARTITION BY HASH(c1) PARTITIONS 4; + +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (126,30); +INSERT INTO t VALUES (127,40); + +SELECT * FROM t ORDER BY c1 ASC; + +if (!$skip_update) +{ +UPDATE t SET c1 = 130 where c1 = 127; +} + +SELECT * FROM t ORDER BY c1 ASC; + +if (!$skip_update) +{ +UPDATE t SET c1 = -140 where c1 = 126; +} + +SELECT * FROM t ORDER BY c1 ASC; + +DROP TABLE t; + +--echo ############################################################################## +} diff --git a/mysql-test/suite/parts/r/partition_auto_increment_innodb.result b/mysql-test/suite/parts/r/partition_auto_increment_innodb.result index 9a23cd4364e..6295d14d98f 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_innodb.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_innodb.result @@ -825,3 +825,194 @@ c1 4 5 DROP TABLE t1; +############################################################################# +# Bug #45823 - Assertion failure in file row/row0mysql.c line 1386 +# Bug #43988 - AUTO_INCREMENT errors with partitioned InnoDB tables in 5.1.31 +############################################################################## +# Inserting negative autoincrement values into a partition table (partitions >= 4) +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='InnoDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +4 40 +DROP TABLE t; +# Reading from a partition table (partitions >= 2 ) after inserting a negative +# value into the auto increment column +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='InnoDB' PARTITION BY HASH(c1) PARTITIONS 2; +INSERT INTO t VALUES (-2,-20); +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-2 -20 +1 30 +DROP TABLE t; +# Inserting negative auto increment value into a partition table (partitions >= 2) +# auto increment value > 2. +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='InnoDB' PARTITION BY HASH(c1) PARTITIONS 2; +INSERT INTO t VALUES (-4,-20); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-4 -20 +1 30 +2 40 +DROP TABLE t; +# Inserting -1 into autoincrement column of a partition table (partition >= 4) +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='InnoDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +DROP TABLE t; +# Deleting from an auto increment table after inserting negative values +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='InnoDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t VALUES (-3,-20); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-3 -20 +-1 -10 +1 10 +2 20 +3 30 +4 40 +DELETE FROM t WHERE c1 > 1; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-3 -20 +-1 -10 +1 10 +DROP TABLE t; +# Inserting a positive value that exceeds maximum allowed value for an +# Auto Increment column (positive maximum) +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='InnoDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (126,30); +INSERT INTO t VALUES (127,40); +INSERT INTO t VALUES (128,50); +ERROR 23000: Duplicate entry '127' for key 'PRIMARY' +INSERT INTO t VALUES (129,60); +ERROR 23000: Duplicate entry '127' for key 'PRIMARY' +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +DROP TABLE t; +# Inserting a negative value that goes below minimum allowed value for an +# Auto Increment column (negative minimum) +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='InnoDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-127,30); +INSERT INTO t VALUES (-128,40); +INSERT INTO t VALUES (-129,50); +ERROR 23000: Duplicate entry '-128' for key 'PRIMARY' +INSERT INTO t VALUES (-130,60); +ERROR 23000: Duplicate entry '-128' for key 'PRIMARY' +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-128 40 +-127 30 +1 10 +2 20 +DROP TABLE t; +# Updating the partition table with a negative Auto Increment value +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='InnoDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +UPDATE t SET c1 = -6 WHERE c1 = 2; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-6 20 +-1 -10 +1 10 +3 30 +INSERT INTO t(c2) VALUES (40); +INSERT INTO t(c2) VALUES (50); +UPDATE t SET c1 = -6 WHERE c1 = 2; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-6 20 +-1 -10 +1 10 +3 30 +4 40 +5 50 +DROP TABLE t; +# Updating the partition table with a value that crosses the upper limits +# on both the positive and the negative side. +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='InnoDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (126,30); +INSERT INTO t VALUES (127,40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +UPDATE t SET c1 = 130 where c1 = 127; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +UPDATE t SET c1 = -140 where c1 = 126; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-128 30 +1 10 +2 20 +127 40 +DROP TABLE t; +############################################################################## diff --git a/mysql-test/suite/parts/r/partition_auto_increment_maria.result b/mysql-test/suite/parts/r/partition_auto_increment_maria.result index 1c1911732ea..419ac10f521 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_maria.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_maria.result @@ -870,3 +870,194 @@ c1 4 5 DROP TABLE t1; +############################################################################# +# Bug #45823 - Assertion failure in file row/row0mysql.c line 1386 +# Bug #43988 - AUTO_INCREMENT errors with partitioned InnoDB tables in 5.1.31 +############################################################################## +# Inserting negative autoincrement values into a partition table (partitions >= 4) +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MARIA' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +4 40 +DROP TABLE t; +# Reading from a partition table (partitions >= 2 ) after inserting a negative +# value into the auto increment column +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MARIA' PARTITION BY HASH(c1) PARTITIONS 2; +INSERT INTO t VALUES (-2,-20); +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-2 -20 +1 30 +DROP TABLE t; +# Inserting negative auto increment value into a partition table (partitions >= 2) +# auto increment value > 2. +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MARIA' PARTITION BY HASH(c1) PARTITIONS 2; +INSERT INTO t VALUES (-4,-20); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-4 -20 +1 30 +2 40 +DROP TABLE t; +# Inserting -1 into autoincrement column of a partition table (partition >= 4) +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MARIA' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +DROP TABLE t; +# Deleting from an auto increment table after inserting negative values +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MARIA' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t VALUES (-3,-20); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-3 -20 +-1 -10 +1 10 +2 20 +3 30 +4 40 +DELETE FROM t WHERE c1 > 1; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-3 -20 +-1 -10 +1 10 +DROP TABLE t; +# Inserting a positive value that exceeds maximum allowed value for an +# Auto Increment column (positive maximum) +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MARIA' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (126,30); +INSERT INTO t VALUES (127,40); +INSERT INTO t VALUES (128,50); +ERROR 23000: Duplicate entry '127' for key 'PRIMARY' +INSERT INTO t VALUES (129,60); +ERROR 23000: Duplicate entry '127' for key 'PRIMARY' +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +DROP TABLE t; +# Inserting a negative value that goes below minimum allowed value for an +# Auto Increment column (negative minimum) +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MARIA' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-127,30); +INSERT INTO t VALUES (-128,40); +INSERT INTO t VALUES (-129,50); +ERROR 23000: Duplicate entry '-128' for key 'PRIMARY' +INSERT INTO t VALUES (-130,60); +ERROR 23000: Duplicate entry '-128' for key 'PRIMARY' +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-128 40 +-127 30 +1 10 +2 20 +DROP TABLE t; +# Updating the partition table with a negative Auto Increment value +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MARIA' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +UPDATE t SET c1 = -6 WHERE c1 = 2; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-6 20 +-1 -10 +1 10 +3 30 +INSERT INTO t(c2) VALUES (40); +INSERT INTO t(c2) VALUES (50); +UPDATE t SET c1 = -6 WHERE c1 = 2; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-6 20 +-1 -10 +1 10 +3 30 +4 40 +5 50 +DROP TABLE t; +# Updating the partition table with a value that crosses the upper limits +# on both the positive and the negative side. +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MARIA' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (126,30); +INSERT INTO t VALUES (127,40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +UPDATE t SET c1 = 130 where c1 = 127; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +UPDATE t SET c1 = -140 where c1 = 126; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-128 30 +1 10 +2 20 +127 40 +DROP TABLE t; +############################################################################## diff --git a/mysql-test/suite/parts/r/partition_auto_increment_memory.result b/mysql-test/suite/parts/r/partition_auto_increment_memory.result index f4d783825f4..6e3b990dc0f 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_memory.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_memory.result @@ -851,3 +851,194 @@ c1 4 5 DROP TABLE t1; +############################################################################# +# Bug #45823 - Assertion failure in file row/row0mysql.c line 1386 +# Bug #43988 - AUTO_INCREMENT errors with partitioned InnoDB tables in 5.1.31 +############################################################################## +# Inserting negative autoincrement values into a partition table (partitions >= 4) +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='Memory' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +4 40 +DROP TABLE t; +# Reading from a partition table (partitions >= 2 ) after inserting a negative +# value into the auto increment column +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='Memory' PARTITION BY HASH(c1) PARTITIONS 2; +INSERT INTO t VALUES (-2,-20); +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-2 -20 +1 30 +DROP TABLE t; +# Inserting negative auto increment value into a partition table (partitions >= 2) +# auto increment value > 2. +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='Memory' PARTITION BY HASH(c1) PARTITIONS 2; +INSERT INTO t VALUES (-4,-20); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-4 -20 +1 30 +2 40 +DROP TABLE t; +# Inserting -1 into autoincrement column of a partition table (partition >= 4) +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='Memory' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +DROP TABLE t; +# Deleting from an auto increment table after inserting negative values +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='Memory' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t VALUES (-3,-20); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-3 -20 +-1 -10 +1 10 +2 20 +3 30 +4 40 +DELETE FROM t WHERE c1 > 1; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-3 -20 +-1 -10 +1 10 +DROP TABLE t; +# Inserting a positive value that exceeds maximum allowed value for an +# Auto Increment column (positive maximum) +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='Memory' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (126,30); +INSERT INTO t VALUES (127,40); +INSERT INTO t VALUES (128,50); +ERROR 23000: Duplicate entry '127' for key 'PRIMARY' +INSERT INTO t VALUES (129,60); +ERROR 23000: Duplicate entry '127' for key 'PRIMARY' +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +DROP TABLE t; +# Inserting a negative value that goes below minimum allowed value for an +# Auto Increment column (negative minimum) +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='Memory' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-127,30); +INSERT INTO t VALUES (-128,40); +INSERT INTO t VALUES (-129,50); +ERROR 23000: Duplicate entry '-128' for key 'PRIMARY' +INSERT INTO t VALUES (-130,60); +ERROR 23000: Duplicate entry '-128' for key 'PRIMARY' +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-128 40 +-127 30 +1 10 +2 20 +DROP TABLE t; +# Updating the partition table with a negative Auto Increment value +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='Memory' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +UPDATE t SET c1 = -6 WHERE c1 = 2; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-6 20 +-1 -10 +1 10 +3 30 +INSERT INTO t(c2) VALUES (40); +INSERT INTO t(c2) VALUES (50); +UPDATE t SET c1 = -6 WHERE c1 = 2; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-6 20 +-1 -10 +1 10 +3 30 +4 40 +5 50 +DROP TABLE t; +# Updating the partition table with a value that crosses the upper limits +# on both the positive and the negative side. +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='Memory' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (126,30); +INSERT INTO t VALUES (127,40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +UPDATE t SET c1 = 130 where c1 = 127; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +UPDATE t SET c1 = -140 where c1 = 126; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-128 30 +1 10 +2 20 +127 40 +DROP TABLE t; +############################################################################## diff --git a/mysql-test/suite/parts/r/partition_auto_increment_myisam.result b/mysql-test/suite/parts/r/partition_auto_increment_myisam.result index 6abf08b68a0..047b974f0a3 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_myisam.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_myisam.result @@ -870,3 +870,194 @@ c1 4 5 DROP TABLE t1; +############################################################################# +# Bug #45823 - Assertion failure in file row/row0mysql.c line 1386 +# Bug #43988 - AUTO_INCREMENT errors with partitioned InnoDB tables in 5.1.31 +############################################################################## +# Inserting negative autoincrement values into a partition table (partitions >= 4) +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MyISAM' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +4 40 +DROP TABLE t; +# Reading from a partition table (partitions >= 2 ) after inserting a negative +# value into the auto increment column +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MyISAM' PARTITION BY HASH(c1) PARTITIONS 2; +INSERT INTO t VALUES (-2,-20); +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-2 -20 +1 30 +DROP TABLE t; +# Inserting negative auto increment value into a partition table (partitions >= 2) +# auto increment value > 2. +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MyISAM' PARTITION BY HASH(c1) PARTITIONS 2; +INSERT INTO t VALUES (-4,-20); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-4 -20 +1 30 +2 40 +DROP TABLE t; +# Inserting -1 into autoincrement column of a partition table (partition >= 4) +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MyISAM' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +DROP TABLE t; +# Deleting from an auto increment table after inserting negative values +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MyISAM' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t VALUES (-3,-20); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-3 -20 +-1 -10 +1 10 +2 20 +3 30 +4 40 +DELETE FROM t WHERE c1 > 1; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-3 -20 +-1 -10 +1 10 +DROP TABLE t; +# Inserting a positive value that exceeds maximum allowed value for an +# Auto Increment column (positive maximum) +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MyISAM' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (126,30); +INSERT INTO t VALUES (127,40); +INSERT INTO t VALUES (128,50); +ERROR 23000: Duplicate entry '127' for key 'PRIMARY' +INSERT INTO t VALUES (129,60); +ERROR 23000: Duplicate entry '127' for key 'PRIMARY' +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +DROP TABLE t; +# Inserting a negative value that goes below minimum allowed value for an +# Auto Increment column (negative minimum) +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MyISAM' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-127,30); +INSERT INTO t VALUES (-128,40); +INSERT INTO t VALUES (-129,50); +ERROR 23000: Duplicate entry '-128' for key 'PRIMARY' +INSERT INTO t VALUES (-130,60); +ERROR 23000: Duplicate entry '-128' for key 'PRIMARY' +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-128 40 +-127 30 +1 10 +2 20 +DROP TABLE t; +# Updating the partition table with a negative Auto Increment value +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MyISAM' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +UPDATE t SET c1 = -6 WHERE c1 = 2; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-6 20 +-1 -10 +1 10 +3 30 +INSERT INTO t(c2) VALUES (40); +INSERT INTO t(c2) VALUES (50); +UPDATE t SET c1 = -6 WHERE c1 = 2; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-6 20 +-1 -10 +1 10 +3 30 +4 40 +5 50 +DROP TABLE t; +# Updating the partition table with a value that crosses the upper limits +# on both the positive and the negative side. +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='MyISAM' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (126,30); +INSERT INTO t VALUES (127,40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +UPDATE t SET c1 = 130 where c1 = 127; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +UPDATE t SET c1 = -140 where c1 = 126; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-128 30 +1 10 +2 20 +127 40 +DROP TABLE t; +############################################################################## diff --git a/mysql-test/suite/parts/r/partition_auto_increment_ndb.result b/mysql-test/suite/parts/r/partition_auto_increment_ndb.result index 5a1c5b06b36..317669be7ad 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_ndb.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_ndb.result @@ -846,3 +846,194 @@ c1 4 5 DROP TABLE t1; +############################################################################# +# Bug #45823 - Assertion failure in file row/row0mysql.c line 1386 +# Bug #43988 - AUTO_INCREMENT errors with partitioned InnoDB tables in 5.1.31 +############################################################################## +# Inserting negative autoincrement values into a partition table (partitions >= 4) +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='NDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +4 40 +DROP TABLE t; +# Reading from a partition table (partitions >= 2 ) after inserting a negative +# value into the auto increment column +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='NDB' PARTITION BY HASH(c1) PARTITIONS 2; +INSERT INTO t VALUES (-2,-20); +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-2 -20 +1 30 +DROP TABLE t; +# Inserting negative auto increment value into a partition table (partitions >= 2) +# auto increment value > 2. +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='NDB' PARTITION BY HASH(c1) PARTITIONS 2; +INSERT INTO t VALUES (-4,-20); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-4 -20 +1 30 +2 40 +DROP TABLE t; +# Inserting -1 into autoincrement column of a partition table (partition >= 4) +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='NDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +DROP TABLE t; +# Deleting from an auto increment table after inserting negative values +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='NDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +INSERT INTO t VALUES (-3,-20); +INSERT INTO t(c2) VALUES (40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-3 -20 +-1 -10 +1 10 +2 20 +3 30 +4 40 +DELETE FROM t WHERE c1 > 1; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-3 -20 +-1 -10 +1 10 +DROP TABLE t; +# Inserting a positive value that exceeds maximum allowed value for an +# Auto Increment column (positive maximum) +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='NDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (126,30); +INSERT INTO t VALUES (127,40); +INSERT INTO t VALUES (128,50); +ERROR 23000: Duplicate entry '127' for key 'PRIMARY' +INSERT INTO t VALUES (129,60); +ERROR 23000: Duplicate entry '127' for key 'PRIMARY' +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +DROP TABLE t; +# Inserting a negative value that goes below minimum allowed value for an +# Auto Increment column (negative minimum) +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='NDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-127,30); +INSERT INTO t VALUES (-128,40); +INSERT INTO t VALUES (-129,50); +ERROR 23000: Duplicate entry '-128' for key 'PRIMARY' +INSERT INTO t VALUES (-130,60); +ERROR 23000: Duplicate entry '-128' for key 'PRIMARY' +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-128 40 +-127 30 +1 10 +2 20 +DROP TABLE t; +# Updating the partition table with a negative Auto Increment value +CREATE TABLE t (c1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='NDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (-1,-10); +INSERT INTO t(c2) VALUES (30); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-1 -10 +1 10 +2 20 +3 30 +UPDATE t SET c1 = -6 WHERE c1 = 2; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-6 20 +-1 -10 +1 10 +3 30 +INSERT INTO t(c2) VALUES (40); +INSERT INTO t(c2) VALUES (50); +UPDATE t SET c1 = -6 WHERE c1 = 2; +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-6 20 +-1 -10 +1 10 +3 30 +4 40 +5 50 +DROP TABLE t; +# Updating the partition table with a value that crosses the upper limits +# on both the positive and the negative side. +CREATE TABLE t (c1 TINYINT NOT NULL AUTO_INCREMENT, PRIMARY KEY(c1), +c2 INT) ENGINE='NDB' PARTITION BY HASH(c1) PARTITIONS 4; +INSERT INTO t(c2) VALUES (10); +INSERT INTO t(c2) VALUES (20); +INSERT INTO t VALUES (126,30); +INSERT INTO t VALUES (127,40); +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +UPDATE t SET c1 = 130 where c1 = 127; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +1 10 +2 20 +126 30 +127 40 +UPDATE t SET c1 = -140 where c1 = 126; +Warnings: +Warning 1264 Out of range value for column 'c1' at row 1 +SELECT * FROM t ORDER BY c1 ASC; +c1 c2 +-128 30 +1 10 +2 20 +127 40 +DROP TABLE t; +############################################################################## diff --git a/mysql-test/suite/parts/r/partition_recover_myisam.result b/mysql-test/suite/parts/r/partition_recover_myisam.result index df737ec2853..49775ee498e 100644 --- a/mysql-test/suite/parts/r/partition_recover_myisam.result +++ b/mysql-test/suite/parts/r/partition_recover_myisam.result @@ -1,3 +1,5 @@ +call mtr.add_suppression("./test/t1_will_crash"); +call mtr.add_suppression("Got an error from unknown thread, ha_myisam.cc"); CREATE TABLE t1_will_crash (a INT, KEY (a)) ENGINE=MyISAM; INSERT INTO t1_will_crash VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11); FLUSH TABLES; diff --git a/mysql-test/suite/parts/t/partition_auto_increment_archive.test b/mysql-test/suite/parts/t/partition_auto_increment_archive.test index fb09557204f..e99a0b23b36 100644 --- a/mysql-test/suite/parts/t/partition_auto_increment_archive.test +++ b/mysql-test/suite/parts/t/partition_auto_increment_archive.test @@ -30,6 +30,9 @@ let $skip_delete= 1; let $skip_truncate= 1; let $skip_update= 1; let $only_ai_pk= 1; +# Bug#45823 Assertion failure in file row/row0mysql.c line 1386 +# Archive does not handle negative autoincrement values correctly +let $skip_negative_auto_inc= 1; ##### Storage engine to be tested let $engine= 'Archive'; diff --git a/mysql-test/suite/parts/t/partition_auto_increment_blackhole.test b/mysql-test/suite/parts/t/partition_auto_increment_blackhole.test index 64cd96c6173..f92dc33f263 100644 --- a/mysql-test/suite/parts/t/partition_auto_increment_blackhole.test +++ b/mysql-test/suite/parts/t/partition_auto_increment_blackhole.test @@ -25,6 +25,9 @@ #------------------------------------------------------------------------------# # Engine specific settings and requirements --source include/have_blackhole.inc +# Bug#45823 Assertion failure in file row/row0mysql.c line 1386 +# Blackhole does not handle negative autoincrement values correctly +let $skip_negative_auto_inc= 1; ##### Storage engine to be tested let $engine= 'Blackhole'; diff --git a/mysql-test/suite/parts/t/partition_recover_myisam.test b/mysql-test/suite/parts/t/partition_recover_myisam.test index dbab4e8f1a2..fe8a51b17cc 100644 --- a/mysql-test/suite/parts/t/partition_recover_myisam.test +++ b/mysql-test/suite/parts/t/partition_recover_myisam.test @@ -1,4 +1,8 @@ # test the auto-recover (--myisam-recover) of partitioned myisam tables + +call mtr.add_suppression("./test/t1_will_crash"); +call mtr.add_suppression("Got an error from unknown thread, ha_myisam.cc"); + --source include/have_partition.inc --disable_warnings --disable_query_log diff --git a/mysql-test/suite/rpl/r/rpl_auto_increment.result b/mysql-test/suite/rpl/r/rpl_auto_increment.result index 17aa592654f..831e9b5c8b5 100644 --- a/mysql-test/suite/rpl/r/rpl_auto_increment.result +++ b/mysql-test/suite/rpl/r/rpl_auto_increment.result @@ -244,3 +244,71 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 drop table t1; +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY) ENGINE=innodb; +CREATE TABLE t2 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY) ENGINE=myisam; +SET SQL_MODE=''; +INSERT INTO t1 VALUES(NULL); +INSERT INTO t2 VALUES(NULL); +SELECT * FROM t1; +id +1 +SELECT * FROM t2; +id +1 +INSERT INTO t1 VALUES(); +INSERT INTO t2 VALUES(); +SELECT * FROM t1; +id +1 +2 +SELECT * FROM t2; +id +1 +2 +INSERT INTO t1 VALUES(0); +INSERT INTO t2 VALUES(0); +SELECT * FROM t1; +id +1 +2 +3 +SELECT * FROM t2; +id +1 +2 +3 +SET SQL_MODE=NO_AUTO_VALUE_ON_ZERO; +INSERT INTO t1 VALUES(0); +INSERT INTO t2 VALUES(0); +SELECT * FROM t1; +id +0 +1 +2 +3 +SELECT * FROM t2; +id +0 +1 +2 +3 +INSERT INTO t1 VALUES(4); +INSERT INTO t2 VALUES(4); +FLUSH LOGS; +Comparing tables master:test.t1 and slave:test.t1 +Comparing tables master:test.t2 and slave:test.t2 +DROP TABLE t1; +DROP TABLE t2; +Comparing tables master:test.t1 and slave:test.t1 +Comparing tables master:test.t2 and slave:test.t2 +DROP TABLE t1; +DROP TABLE t2; +SET SQL_MODE=''; diff --git a/mysql-test/suite/rpl/r/rpl_auto_increment_update_failure.result b/mysql-test/suite/rpl/r/rpl_auto_increment_update_failure.result new file mode 100644 index 00000000000..b2cc92491c3 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_auto_increment_update_failure.result @@ -0,0 +1,1041 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +# Test case1: INVOKES A TRIGGER with after insert action +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr1 after insert on t1 for each row insert into t2(a) values(6); +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +create trigger tr2 after insert on t3 for each row begin +insert into t4(a) values(f1_insert_triggered()); +insert into t4(a) values(f1_insert_triggered()); +insert into t5(a) values(8); +end | +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN +INSERT INTO t6(a) values(2),(3); +RETURN 1; +END// +begin; +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; +insert into t2(a) values(3); +insert into t4(a) values(3); +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t4(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 1 +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 1 +master-bin.000001 # Query # # use `test`; delete from t1 where b = 1 +master-bin.000001 # Query # # use `test`; delete from t3 where b = 1 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t1 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t3 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'INVOKES A TRIGGER with after insert action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t4 and slave:test.t4 +Comparing tables master:test.t6 and slave:test.t6 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +# Test case2: INVOKES A TRIGGER with before insert action +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr1 before insert on t1 for each row insert into t2(a) values(6); +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +create trigger tr2 before insert on t3 for each row begin +insert into t4(a) values(f1_insert_triggered()); +insert into t4(a) values(f1_insert_triggered()); +insert into t5(a) values(8); +end | +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN +INSERT INTO t6(a) values(2),(3); +RETURN 1; +END// +begin; +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; +insert into t2(a) values(3); +insert into t4(a) values(3); +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t4(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 1 +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 1 +master-bin.000001 # Query # # use `test`; delete from t1 where b = 1 +master-bin.000001 # Query # # use `test`; delete from t3 where b = 1 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t1 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t3 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'INVOKES A TRIGGER with before insert action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t4 and slave:test.t4 +Comparing tables master:test.t6 and slave:test.t6 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +# Test case3: INVOKES A TRIGGER with after update action +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr1 after update on t1 for each row insert into t2(a) values(6); +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +create trigger tr2 after update on t3 for each row begin +insert into t4(a) values(f1_insert_triggered()); +insert into t4(a) values(f1_insert_triggered()); +insert into t5(a) values(8); +end | +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN +INSERT INTO t6(a) values(2),(3); +RETURN 1; +END// +begin; +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; +insert into t2(a) values(3); +insert into t4(a) values(3); +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t4(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(1,1),(2,1) +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(1,1),(2,1) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; delete from t1 where b = 1 +master-bin.000001 # Query # # use `test`; delete from t3 where b = 1 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t1 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t3 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'INVOKES A TRIGGER with after update action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t4 and slave:test.t4 +Comparing tables master:test.t6 and slave:test.t6 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +# Test case4: INVOKES A TRIGGER with before update action +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr1 before update on t1 for each row insert into t2(a) values(6); +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +create trigger tr2 before update on t3 for each row begin +insert into t4(a) values(f1_insert_triggered()); +insert into t4(a) values(f1_insert_triggered()); +insert into t5(a) values(8); +end | +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN +INSERT INTO t6(a) values(2),(3); +RETURN 1; +END// +begin; +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; +insert into t2(a) values(3); +insert into t4(a) values(3); +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t4(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(1,1),(2,1) +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(1,1),(2,1) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; delete from t1 where b = 1 +master-bin.000001 # Query # # use `test`; delete from t3 where b = 1 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t1 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; delete from t3 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'INVOKES A TRIGGER with before update action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t4 and slave:test.t4 +Comparing tables master:test.t6 and slave:test.t6 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +# Test case5: INVOKES A TRIGGER with after delete action +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr1 after delete on t1 for each row insert into t2(a) values(6); +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +create trigger tr2 after delete on t3 for each row begin +insert into t4(a) values(f1_insert_triggered()); +insert into t4(a) values(f1_insert_triggered()); +insert into t5(a) values(8); +end | +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN +INSERT INTO t6(a) values(2),(3); +RETURN 1; +END// +begin; +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; +insert into t2(a) values(3); +insert into t4(a) values(3); +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t4(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(1,1),(2,1) +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(1,1),(2,1) +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 1 +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 1 +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'INVOKES A TRIGGER with after delete action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t4 and slave:test.t4 +Comparing tables master:test.t6 and slave:test.t6 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +# Test case6: INVOKES A TRIGGER with before delete action +create table t1(a int, b int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr1 before delete on t1 for each row insert into t2(a) values(6); +create table t3(a int, b int) engine=innodb; +create table t4(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t5(a int) engine=innodb; +create trigger tr2 before delete on t3 for each row begin +insert into t4(a) values(f1_insert_triggered()); +insert into t4(a) values(f1_insert_triggered()); +insert into t5(a) values(8); +end | +create table t6(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_insert_triggered() RETURNS INTEGER +BEGIN +INSERT INTO t6(a) values(2),(3); +RETURN 1; +END// +begin; +insert into t1(a,b) values(1,1),(2,1); +insert into t3(a,b) values(1,1),(2,1); +update t1 set a = a + 5 where b = 1; +update t3 set a = a + 5 where b = 1; +delete from t1 where b = 1; +delete from t3 where b = 1; +insert into t2(a) values(3); +insert into t4(a) values(3); +commit; +insert into t1(a,b) values(4,2); +insert into t3(a,b) values(4,2); +update t1 set a = a + 5 where b = 2; +update t3 set a = a + 5 where b = 2; +delete from t1 where b = 2; +delete from t3 where b = 2; +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; insert into t4(a) values(3) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(1,1),(2,1) +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(1,1),(2,1) +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 1 +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 1 +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; insert into t3(a,b) values(4,2) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t1 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; update t3 set a = a + 5 where b = 2 +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t5) +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t6) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'INVOKES A TRIGGER with before delete action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t4 and slave:test.t4 +Comparing tables master:test.t6 and slave:test.t6 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP TABLE t5; +DROP TABLE t6; +DROP FUNCTION f1_insert_triggered; +# Test case7: CALLS A FUNCTION which INVOKES A TRIGGER with after insert action +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t3(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_two_inserts_trigger() RETURNS INTEGER +BEGIN +INSERT INTO t2(a) values(2),(3); +INSERT INTO t2(a) values(2),(3); +RETURN 1; +END | +create trigger tr11 after insert on t2 for each row begin +insert into t3(a) values(new.a); +insert into t3(a) values(new.a); +end | +begin; +insert into t1(a) values(f1_two_inserts_trigger()); +insert into t2(a) values(4),(5); +commit; +insert into t1(a) values(f1_two_inserts_trigger()); +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'CALLS A FUNCTION which INVOKES A TRIGGER with after insert action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t3 and slave:test.t3 +drop table t1; +drop table t2; +drop table t3; +drop function f1_two_inserts_trigger; +# Test case8: CALLS A FUNCTION which INVOKES A TRIGGER with before insert action +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create table t3(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_two_inserts_trigger() RETURNS INTEGER +BEGIN +INSERT INTO t2(a) values(2),(3); +INSERT INTO t2(a) values(2),(3); +RETURN 1; +END | +create trigger tr11 before insert on t2 for each row begin +insert into t3(a) values(new.a); +insert into t3(a) values(new.a); +end | +begin; +insert into t1(a) values(f1_two_inserts_trigger()); +insert into t2(a) values(4),(5); +commit; +insert into t1(a) values(f1_two_inserts_trigger()); +# To verify if insert/update in an autoinc column causes statement to be logged in row format +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Xid # # COMMIT /* XID */ +commit; +#Test if the results are consistent on master and slave +#for 'CALLS A FUNCTION which INVOKES A TRIGGER with before insert action' +Comparing tables master:test.t2 and slave:test.t2 +Comparing tables master:test.t3 and slave:test.t3 +drop table t1; +drop table t2; +drop table t3; +drop function f1_two_inserts_trigger; +# Test case9: INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS with after insert action +CREATE TABLE t1(i1 int not null auto_increment, c1 INT, primary key(i1)) engine=innodb; +CREATE TABLE t2(i1 int not null auto_increment, c2 INT, primary key(i1)) engine=innodb; +CREATE TABLE t3(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr16 after insert on t1 for each row insert into t3(a) values(new.c1); +create trigger tr17 after insert on t2 for each row insert into t3(a) values(new.c2); +begin; +INSERT INTO t1(c1) VALUES (11), (12); +INSERT INTO t2(c2) VALUES (13), (14); +CREATE VIEW v16 AS SELECT c1, c2 FROM t1, t2; +INSERT INTO v16(c1) VALUES (15),(16); +INSERT INTO v16(c2) VALUES (17),(18); +INSERT INTO v16(c1) VALUES (19),(20); +INSERT INTO v16(c2) VALUES (21),(22); +INSERT INTO v16(c1) VALUES (23), (24); +INSERT INTO v16(c1) VALUES (25), (26); +commit; +#Test if the results are consistent on master and slave +#for 'INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS' +Comparing tables master:test.t3 and slave:test.t3 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP VIEW v16; +# Test case10: INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS with before insert action +CREATE TABLE t1(i1 int not null auto_increment, c1 INT, primary key(i1)) engine=innodb; +CREATE TABLE t2(i1 int not null auto_increment, c2 INT, primary key(i1)) engine=innodb; +CREATE TABLE t3(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +create trigger tr16 before insert on t1 for each row insert into t3(a) values(new.c1); +create trigger tr17 before insert on t2 for each row insert into t3(a) values(new.c2); +begin; +INSERT INTO t1(c1) VALUES (11), (12); +INSERT INTO t2(c2) VALUES (13), (14); +CREATE VIEW v16 AS SELECT c1, c2 FROM t1, t2; +INSERT INTO v16(c1) VALUES (15),(16); +INSERT INTO v16(c2) VALUES (17),(18); +INSERT INTO v16(c1) VALUES (19),(20); +INSERT INTO v16(c2) VALUES (21),(22); +INSERT INTO v16(c1) VALUES (23), (24); +INSERT INTO v16(c1) VALUES (25), (26); +commit; +#Test if the results are consistent on master and slave +#for 'INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS' +Comparing tables master:test.t3 and slave:test.t3 +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP VIEW v16; +# Test case11: INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES INTO A TABLE WITH AUTOINC COLUMN +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_two_inserts() RETURNS INTEGER +BEGIN +INSERT INTO t2(a) values(2); +INSERT INTO t2(a) values(2); +RETURN 1; +END// +begin; +insert into t1(a) values(f1_two_inserts()); +insert into t2(a) values(4),(5); +commit; +insert into t1(a) values(f1_two_inserts()); +commit; +#Test result for INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES on master +select * from t2 ORDER BY i1; +i1 a +1 2 +2 2 +3 4 +4 5 +5 2 +6 2 +#Test result for INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES on slave +select * from t2 ORDER BY i1; +i1 a +1 2 +2 2 +3 4 +4 5 +5 2 +6 2 +drop table t1; +drop table t2; +drop function f1_two_inserts; +# Test case12: INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES OF A TABLE WITH AUTOINC COLUMN +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +CREATE FUNCTION f1_two_updates() RETURNS INTEGER +BEGIN +update t2 set a = a + 5 where b = 1; +update t2 set a = a + 5 where b = 2; +update t2 set a = a + 5 where b = 3; +update t2 set a = a + 5 where b = 4; +RETURN 1; +END// +insert into t2(a,b) values(1,1); +insert into t2(a,b) values(2,2); +insert into t2(a,b) values(3,3); +insert into t2(a,b) values(4,4); +insert into t1(a) values(f1_two_updates()); +begin; +insert into t1(a) values(f1_two_updates()); +commit; +#Test result for INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES on master +select * from t2 ORDER BY i1; +i1 a b +1 11 1 +2 12 2 +3 13 3 +4 14 4 +#Test result for INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES on slave +select * from t2 ORDER BY i1; +i1 a b +1 11 1 +2 12 2 +3 13 3 +4 14 4 +drop table t1; +drop table t2; +drop function f1_two_updates; +# Test case13: UPDATE MORE THAN ONE TABLES ON TOP-STATEMENT +create table t1(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +create table t2(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +begin; +insert into t1(a,b) values(1,1),(2,2); +insert into t2(a,b) values(1,1),(2,2); +update t1,t2 set t1.a=t1.a+5, t2.a=t2.a+5 where t1.b=t2.b; +insert into t1(a,b) values(3,3); +insert into t2(a,b) values(3,3); +commit; +# To verify if it works fine when these statements are not be marked as unsafe +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(1,1),(2,2) +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; insert into t2(a,b) values(1,1),(2,2) +master-bin.000001 # Query # # use `test`; update t1,t2 set t1.a=t1.a+5, t2.a=t2.a+5 where t1.b=t2.b +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t1(a,b) values(3,3) +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2(a,b) values(3,3) +master-bin.000001 # Xid # # COMMIT /* XID */ +#Test if the results are consistent on master and slave +#for 'UPDATE MORE THAN ONE TABLES ON TOP-STATEMENT' +Comparing tables master:test.t1 and slave:test.t1 +Comparing tables master:test.t2 and slave:test.t2 +drop table t1; +drop table t2; +# Test case14: INSERT DATA INTO VIEW WHICH INVOLVED MORE THAN ONE TABLES +CREATE TABLE t1(i1 int not null auto_increment, c1 INT, primary key(i1)) engine=innodb; +CREATE TABLE t2(i1 int not null auto_increment, c2 INT, primary key(i1)) engine=innodb; +begin; +INSERT INTO t1(c1) VALUES (11), (12); +INSERT INTO t2(c2) VALUES (13), (14); +CREATE VIEW v15 AS SELECT c1, c2 FROM t1, t2; +INSERT INTO v15(c1) VALUES (15),(16); +INSERT INTO v15(c2) VALUES (17),(18); +INSERT INTO v15(c1) VALUES (19),(20); +INSERT INTO v15(c2) VALUES (21),(22); +INSERT INTO v15(c1) VALUES (23), (24); +INSERT INTO v15(c2) VALUES (25), (26); +commit; +# To verify if it works fine when these statements are not be marked as unsafe +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; INSERT INTO t1(c1) VALUES (11), (12) +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; INSERT INTO t2(c2) VALUES (13), (14) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v15` AS SELECT c1, c2 FROM t1, t2 +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; INSERT INTO v15(c1) VALUES (15),(16) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; INSERT INTO v15(c2) VALUES (17),(18) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; INSERT INTO v15(c1) VALUES (19),(20) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=5 +master-bin.000001 # Query # # use `test`; INSERT INTO v15(c2) VALUES (21),(22) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Query # # use `test`; INSERT INTO v15(c1) VALUES (23), (24) +master-bin.000001 # Xid # # COMMIT /* XID */ +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Query # # use `test`; INSERT INTO v15(c2) VALUES (25), (26) +master-bin.000001 # Xid # # COMMIT /* XID */ +#Test if the results are consistent on master and slave +#for 'INSERT DATA INTO VIEW WHICH INVOLVED MORE THAN ONE TABLES' +Comparing tables master:test.t1 and slave:test.t1 +Comparing tables master:test.t2 and slave:test.t2 +drop table t1; +drop table t2; +drop view v15; diff --git a/mysql-test/suite/rpl/r/rpl_bug33931.result b/mysql-test/suite/rpl/r/rpl_bug33931.result index 85c8fb0da9c..a17941f6ba9 100644 --- a/mysql-test/suite/rpl/r/rpl_bug33931.result +++ b/mysql-test/suite/rpl/r/rpl_bug33931.result @@ -1,5 +1,5 @@ reset master; -call mtr.add_suppression("Failed during slave thread initialization"); +call mtr.add_suppression("Failed during slave I/O thread initialization"); stop slave; reset slave; SET GLOBAL debug="d,simulate_io_slave_error_on_init,simulate_sql_slave_error_on_init"; diff --git a/mysql-test/suite/rpl/r/rpl_do_grant.result b/mysql-test/suite/rpl/r/rpl_do_grant.result index 69bcfad4347..0913b1afdbf 100644 --- a/mysql-test/suite/rpl/r/rpl_do_grant.result +++ b/mysql-test/suite/rpl/r/rpl_do_grant.result @@ -166,4 +166,7 @@ DROP FUNCTION upgrade_del_func; DROP FUNCTION upgrade_alter_func; DROP DATABASE bug42217_db; DROP USER 'create_rout_db'@'localhost'; +call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' Error_code: 1396"); +USE mtr; +call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' Error_code: 1396"); "End of test" diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result index e57daad3342..e2ec78e7adc 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +call mtr.add_suppression("Slave: Unknown table 't6' Error_code: 1051"); **** Diff Table Def Start **** *** On Slave *** STOP SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result index 6696ddc7789..ed5b4eac27d 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +call mtr.add_suppression("Slave: Unknown table 't6' Error_code: 1051"); **** Diff Table Def Start **** *** On Slave *** STOP SLAVE; diff --git a/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result b/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result index e4d5127ac07..5f2a55b5e35 100644 --- a/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result +++ b/mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result @@ -4,6 +4,10 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +call mtr.add_suppression("Get master clock failed with error: "); +call mtr.add_suppression("Get master SERVER_ID failed with error: "); +call mtr.add_suppression("Slave I/O: Master command COM_REGISTER_SLAVE failed: failed registering on master, reconnecting to try again"); +call mtr.add_suppression("Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids; .*"); SELECT IS_FREE_LOCK("debug_lock.before_get_UNIX_TIMESTAMP"); IS_FREE_LOCK("debug_lock.before_get_UNIX_TIMESTAMP") 1 diff --git a/mysql-test/suite/rpl/r/rpl_idempotency.result b/mysql-test/suite/rpl/r/rpl_idempotency.result index 3341c03db0f..bfdcbc6fa23 100644 --- a/mysql-test/suite/rpl/r/rpl_idempotency.result +++ b/mysql-test/suite/rpl/r/rpl_idempotency.result @@ -4,7 +4,8 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -call mtr.add_suppression("Slave: Can\'t find record in \'t1\' Error_code: 1032"); +call mtr.add_suppression("Slave: Can't find record in 't.' Error_code: 1032"); +call mtr.add_suppression("Slave: Cannot delete or update a parent row: a foreign key constraint fails .* Error_code: 1451"); call mtr.add_suppression("Slave: Cannot add or update a child row: a foreign key constraint fails .* Error_code: 1452"); SET @old_slave_exec_mode= @@global.slave_exec_mode; CREATE TABLE t1 (a INT PRIMARY KEY); diff --git a/mysql-test/suite/rpl/r/rpl_init_slave_errors.result b/mysql-test/suite/rpl/r/rpl_init_slave_errors.result index ab957e6d9bc..c6ee82b13f3 100644 --- a/mysql-test/suite/rpl/r/rpl_init_slave_errors.result +++ b/mysql-test/suite/rpl/r/rpl_init_slave_errors.result @@ -9,6 +9,7 @@ reset slave; SET GLOBAL debug= "d,simulate_io_slave_error_on_init,simulate_sql_slave_error_on_init"; start slave; Reporting the following error: Failed during slave thread initialization +call mtr.add_suppression("Failed during slave I/O thread initialization"); SET GLOBAL debug= ""; stop slave; reset slave; diff --git a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result index 81c486cb43c..3a1c2b68b01 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result @@ -885,7 +885,7 @@ master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2 master-bin.000001 # Xid 1 # # master-bin.000001 # Query 1 # BEGIN master-bin.000001 # Begin_load_query 1 # ;file_id=#;block_len=# -master-bin.000001 # Execute_load_query 1 # use `test_rpl`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/std_data/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ;file_id=# +master-bin.000001 # Execute_load_query 1 # use `test_rpl`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/std_data/rpl_mixed.dat' INTO TABLE `t1` FIELDS TERMINATED BY '|' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (a, b) ;file_id=# master-bin.000001 # Xid 1 # # master-bin.000001 # Query 1 # BEGIN master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 diff --git a/mysql-test/suite/rpl/r/rpl_loaddata.result b/mysql-test/suite/rpl/r/rpl_loaddata.result index d7a02bc84a5..ca9c14691b0 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata.result @@ -36,7 +36,7 @@ set global sql_slave_skip_counter=1; start slave; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error -# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1797 # # master-bin.000001 Yes Yes # 0 0 1797 # None 0 No # No 0 0 +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 2009 # # master-bin.000001 Yes Yes # 0 0 2009 # None 0 No # No 0 0 set sql_log_bin=0; delete from t1; set sql_log_bin=1; @@ -46,7 +46,7 @@ change master to master_user='test'; change master to master_user='root'; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error -# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1832 # # master-bin.000001 No No # 0 0 1832 # None 0 No # No 0 0 +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 2044 # # master-bin.000001 No No # 0 0 2044 # None 0 No # No 0 0 set global sql_slave_skip_counter=1; start slave; set sql_log_bin=0; @@ -86,3 +86,32 @@ CREATE TABLE t1 (word CHAR(20) NOT NULL PRIMARY KEY) ENGINE=INNODB; LOAD DATA INFILE "../../std_data/words.dat" INTO TABLE t1; ERROR 23000: Duplicate entry 'Aarhus' for key 'PRIMARY' DROP TABLE IF EXISTS t1; +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +drop database if exists b48297_db1; +drop database if exists b42897_db2; +create database b48297_db1; +create database b42897_db2; +use b48297_db1; +CREATE TABLE t1 (c1 VARCHAR(256)) engine=MyISAM;; +use b42897_db2; +### assertion: works with cross-referenced database +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1; +use b48297_db1; +### assertion: works with fully qualified name on current database +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1; +### assertion: works without fully qualified name on current database +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE t1; +### create connection without default database +### connect (conn2,localhost,root,,*NO-ONE*); +### assertion: works without stating the default database +LOAD DATA LOCAL INFILE 'MYSQLTEST_VARDIR/std_data/loaddata5.dat' INTO TABLE b48297_db1.t1; +### disconnect and switch back to master connection +use b48297_db1; +Comparing tables master:b48297_db1.t1 and slave:b48297_db1.t1 +DROP DATABASE b48297_db1; +DROP DATABASE b42897_db2; diff --git a/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result b/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result index 27fb8623e85..35696615b5a 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata_fatal.result @@ -53,7 +53,7 @@ Master_User root Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 465 +Read_Master_Log_Pos 556 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 diff --git a/mysql-test/suite/rpl/r/rpl_loaddata_map.result b/mysql-test/suite/rpl/r/rpl_loaddata_map.result index 901f3352b44..006f84043a4 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddata_map.result +++ b/mysql-test/suite/rpl/r/rpl_loaddata_map.result @@ -20,7 +20,7 @@ master-bin.000001 # Query # # use `test`; create table t2 (id int not null prima master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# master-bin.000001 # Append_block # # ;file_id=#;block_len=# master-bin.000001 # Append_block # # ;file_id=#;block_len=# -master-bin.000001 # Execute_load_query # # use `test`; load data infile 'MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' into table t2 ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug30435_5k.txt' INTO TABLE `t2` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (id) ;file_id=# ==== Verify results on slave ==== [on slave] select count(*) from t2 /* 5 000 */; diff --git a/mysql-test/suite/rpl/r/rpl_loaddatalocal.result b/mysql-test/suite/rpl/r/rpl_loaddatalocal.result index 93ef33f3fc0..6dccaa3d74c 100644 --- a/mysql-test/suite/rpl/r/rpl_loaddatalocal.result +++ b/mysql-test/suite/rpl/r/rpl_loaddatalocal.result @@ -54,3 +54,31 @@ a [on master] DROP TABLE t1; [on slave] + +Bug #43746: +"return wrong query string when parse 'load data infile' sql statement" + +[master] +SELECT @@SESSION.sql_mode INTO @old_mode; +SET sql_mode='ignore_space'; +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES (1), (2), (3), (4); +SELECT * INTO OUTFILE 'MYSQLD_DATADIR/bug43746.sql' FROM t1; +TRUNCATE TABLE t1; +LOAD DATA LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; +LOAD/* look mum, with comments in weird places! */DATA/* oh hai */LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql'/* we are */INTO/* from the internets */TABLE t1; +LOAD DATA/*!10000 LOCAL */INFILE 'MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; +LOAD DATA LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql' /*!10000 INTO */ TABLE t1; +LOAD DATA LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql' /*!10000 INTO TABLE */ t1; +LOAD DATA /*!10000 LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql' INTO TABLE */ t1; +LOAD DATA/*!10000 LOCAL */INFILE 'MYSQLD_DATADIR/bug43746.sql'/*!10000 INTO*/TABLE t1; +LOAD DATA/*!10000 LOCAL */INFILE 'MYSQLD_DATADIR/bug43746.sql'/* empty */INTO TABLE t1; +LOAD DATA/*!10000 LOCAL */INFILE 'MYSQLD_DATADIR/bug43746.sql' INTO/* empty */TABLE t1; +LOAD/*!99999 special comments that do not expand */DATA/*!99999 code from the future */LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql'/*!99999 have flux capacitor */INTO/*!99999 will travel */TABLE t1; +SET sql_mode='PIPES_AS_CONCAT,ANSI_QUOTES,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER'; +LOAD DATA LOCAL INFILE 'MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; +[slave] +[master] +DROP TABLE t1; +SET SESSION sql_mode=@old_mode; +[slave] diff --git a/mysql-test/suite/rpl/r/rpl_log_pos.result b/mysql-test/suite/rpl/r/rpl_log_pos.result index 7b3ebf62959..85fa4c10eac 100644 --- a/mysql-test/suite/rpl/r/rpl_log_pos.result +++ b/mysql-test/suite/rpl/r/rpl_log_pos.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +call mtr.add_suppression ("Slave I/O: Got fatal error 1236 from master when reading data from binary"); show master status; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 # <Binlog_Do_DB> <Binlog_Ignore_DB> diff --git a/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result b/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result new file mode 100644 index 00000000000..09a9121d22c --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_mysql_upgrade.result @@ -0,0 +1,13 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +DROP DATABASE IF EXISTS `#mysql50#mysqltest-1`; +CREATE DATABASE `#mysql50#mysqltest-1`; +Master position is not changed +STOP SLAVE SQL_THREAD; +Master position has been changed +DROP DATABASE `mysqltest-1`; +DROP DATABASE `#mysql50#mysqltest-1`; diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index 4c64054e348..0a9495751fe 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -4,6 +4,8 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +call mtr.add_suppression("Slave I/O: Got a packet bigger than 'max_allowed_packet' bytes, Error_code: 1153"); +call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log:"); drop database if exists DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; create database DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; SET @@global.max_allowed_packet=1024; @@ -32,6 +34,21 @@ include/start_slave.inc CREATE TABLE `t1` (`f1` LONGTEXT) ENGINE=MyISAM; INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048'); Slave_IO_Running = No (expect No) +SELECT "Got a packet bigger than 'max_allowed_packet' bytes" AS Last_IO_Error; +Last_IO_Error +Got a packet bigger than 'max_allowed_packet' bytes +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TABLE t1 (f1 int PRIMARY KEY, f2 LONGTEXT, f3 LONGTEXT) ENGINE=MyISAM; +INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), REPEAT('b', @@global.max_allowed_packet)); +Slave_IO_Running = No (expect No) +SELECT "Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master'" AS Last_IO_Error; +Last_IO_Error +Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master' ==== clean up ==== DROP TABLE t1; SET @@global.max_allowed_packet= 1024; diff --git a/mysql-test/suite/rpl/r/rpl_row_create_table.result b/mysql-test/suite/rpl/r/rpl_row_create_table.result index 5bed9106009..b7122adea2a 100644 --- a/mysql-test/suite/rpl/r/rpl_row_create_table.result +++ b/mysql-test/suite/rpl/r/rpl_row_create_table.result @@ -176,7 +176,7 @@ Log_name Pos Event_type Server_id End_log_pos Info # 106 Query # 174 BEGIN # 174 Table_map # 216 table_id: # (test.t7) # 216 Write_rows # 272 table_id: # flags: STMT_END_F -# 272 Query # 343 ROLLBACK +# 272 Query # 341 COMMIT SELECT * FROM t7 ORDER BY a,b; a b 1 2 @@ -327,7 +327,7 @@ Log_name Pos Event_type Server_id End_log_pos Info # 1329 Query # 1397 BEGIN # 1397 Table_map # 1438 table_id: # (test.t1) # 1438 Write_rows # 1482 table_id: # flags: STMT_END_F -# 1482 Query # 1553 ROLLBACK +# 1482 Query # 1551 COMMIT SHOW TABLES; Tables_in_test t1 diff --git a/mysql-test/suite/rpl/r/rpl_row_disabled_slave_key.result b/mysql-test/suite/rpl/r/rpl_row_disabled_slave_key.result new file mode 100644 index 00000000000..01e3dfd6508 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_row_disabled_slave_key.result @@ -0,0 +1,26 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +SET SQL_LOG_BIN=0; +CREATE TABLE t (a int, b int, c int, key(b)); +SET SQL_LOG_BIN=1; +CREATE TABLE t (a int, b int, c int); +INSERT INTO t VALUES (1,2,4); +INSERT INTO t VALUES (4,3,4); +DELETE FROM t; +DROP TABLE t; +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TABLE t (a int, b int, c int, key(b)); +ALTER TABLE t DISABLE KEYS; +INSERT INTO t VALUES (1,2,4); +INSERT INTO t VALUES (4,3,4); +DELETE FROM t; +DROP TABLE t; diff --git a/mysql-test/suite/rpl/r/rpl_row_sp006_InnoDB.result b/mysql-test/suite/rpl/r/rpl_row_sp006_InnoDB.result index 8339e77d3a0..6792a701577 100644 --- a/mysql-test/suite/rpl/r/rpl_row_sp006_InnoDB.result +++ b/mysql-test/suite/rpl/r/rpl_row_sp006_InnoDB.result @@ -4,21 +4,20 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -create database if not exists mysqltest1; -DROP PROCEDURE IF EXISTS mysqltest1.p1; -DROP PROCEDURE IF EXISTS mysqltest1.p2; -DROP TABLE IF EXISTS mysqltest1.t2; -DROP TABLE IF EXISTS mysqltest1.t1; -CREATE TABLE IF NOT EXISTS mysqltest1.t1(name CHAR(16), birth DATE,PRIMARY KEY(name))ENGINE=InnoDB; -CREATE TABLE IF NOT EXISTS mysqltest1.t2(name CHAR(16), age INT ,PRIMARY KEY(name))ENGINE=InnoDB; -CREATE PROCEDURE mysqltest1.p1() +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +CREATE TABLE IF NOT EXISTS t1(name CHAR(16), birth DATE,PRIMARY KEY(name))ENGINE=InnoDB; +CREATE TABLE IF NOT EXISTS t2(name CHAR(16), age INT ,PRIMARY KEY(name))ENGINE=InnoDB; +CREATE PROCEDURE p1() BEGIN DECLARE done INT DEFAULT 0; DECLARE spa CHAR(16); DECLARE spb INT; DECLARE cur1 CURSOR FOR SELECT name, (YEAR(CURDATE())-YEAR(birth))-(RIGHT(CURDATE(),5)<RIGHT(birth,5)) -FROM mysqltest1.t1; +FROM t1; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; OPEN cur1; SET AUTOCOMMIT=0; @@ -26,21 +25,20 @@ REPEAT FETCH cur1 INTO spa, spb; IF NOT done THEN START TRANSACTION; -INSERT INTO mysqltest1.t2 VALUES (spa,spb); +INSERT INTO t2 VALUES (spa,spb); COMMIT; END IF; UNTIL done END REPEAT; SET AUTOCOMMIT=1; CLOSE cur1; END| -CREATE PROCEDURE mysqltest1.p2() +CREATE PROCEDURE p2() BEGIN -INSERT INTO mysqltest1.t1 VALUES ('MySQL','1993-02-04'),('ROCKS', '1990-08-27'),('Texas', '1999-03-30'),('kyle','2005-1-1'); +INSERT INTO t1 VALUES ('MySQL','1993-02-04'),('ROCKS', '1990-08-27'),('Texas', '1999-03-30'),('kyle','2005-1-1'); END| -CALL mysqltest1.p2(); -CALL mysqltest1.p1(); -DROP PROCEDURE IF EXISTS mysqltest1.p1; -DROP PROCEDURE IF EXISTS mysqltest1.p2; -DROP TABLE IF EXISTS mysqltest1.t1; -DROP TABLE IF EXISTS mysqltest1.t2; -DROP DATABASE mysqltest1; +CALL p2(); +CALL p1(); +DROP TABLE t1; +DROP TABLE t2; +DROP PROCEDURE p1; +DROP PROCEDURE p2; diff --git a/mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result b/mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result index 777f7d8427b..e2efcf08d7a 100644 --- a/mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result +++ b/mysql-test/suite/rpl/r/rpl_slave_load_remove_tmpfile.result @@ -51,3 +51,4 @@ Last_SQL_Errno 9 Last_SQL_Error Error in Begin_load_query event: write to '../../tmp/SQL_LOAD.data' failed drop table t1; drop table t1; +call mtr.add_suppression("Slave: Error writing file 'UNKNOWN' .Errcode: 9. Error_code: 3"); diff --git a/mysql-test/suite/rpl/r/rpl_stm_log.result b/mysql-test/suite/rpl/r/rpl_stm_log.result index bcefc6f9d3d..d73b8990041 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_log.result +++ b/mysql-test/suite/rpl/r/rpl_stm_log.result @@ -25,7 +25,7 @@ master-bin.000001 # Query 1 # use `test`; insert into t1 values (NULL) master-bin.000001 # Query 1 # use `test`; drop table t1 master-bin.000001 # Query 1 # use `test`; create table t1 (word char(20) not null)ENGINE=MyISAM master-bin.000001 # Begin_load_query 1 # ;file_id=1;block_len=581 -master-bin.000001 # Execute_load_query 1 # use `test`; load data infile '../../std_data/words.dat' into table t1 ignore 1 lines ;file_id=1 +master-bin.000001 # Execute_load_query 1 # use `test`; LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' IGNORE 1 LINES (word) ;file_id=1 show binlog events from 106 limit 1; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM @@ -193,7 +193,7 @@ master-bin.000001 # Query # # use `test`; insert into t1 values (NULL) master-bin.000001 # Query # # use `test`; drop table t1 master-bin.000001 # Query # # use `test`; create table t1 (word char(20) not null)ENGINE=MyISAM master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=# -master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/words.dat' into table t1 ignore 1 lines ;file_id=# +master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE '../../std_data/words.dat' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' IGNORE 1 LINES (word) ;file_id=# master-bin.000001 # Rotate # # master-bin.000002;pos=4 show binlog events in 'master-bin.000002'; Log_name Pos Event_type Server_id End_log_pos Info @@ -218,7 +218,7 @@ slave-bin.000001 # Query 1 # use `test`; insert into t1 values (NULL) slave-bin.000001 # Query 1 # use `test`; drop table t1 slave-bin.000001 # Query 1 # use `test`; create table t1 (word char(20) not null)ENGINE=MyISAM slave-bin.000001 # Begin_load_query 1 # ;file_id=1;block_len=581 -slave-bin.000001 # Execute_load_query 1 # use `test`; load data INFILE '../../tmp/SQL_LOAD-2-1-1.data' INTO table t1 ignore 1 lines ;file_id=1 +slave-bin.000001 # Execute_load_query 1 # use `test`; LOAD DATA INFILE '../../tmp/SQL_LOAD-2-1-1.data' INTO TABLE `t1` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' IGNORE 1 LINES (word) ;file_id=1 slave-bin.000001 # Query 1 # use `test`; create table t3 (a int)ENGINE=MyISAM slave-bin.000001 # Rotate 2 # slave-bin.000002;pos=4 show binlog events in 'slave-bin.000002' from 4; diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index af8eef764ed..8cae44a3607 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -10,6 +10,3 @@ # ############################################################################## -rpl_cross_version : Bug#42311 2009-03-27 joro rpl_cross_version fails on macosx -rpl_init_slave : Bug#44920 2009-07006 pcrews MTR2 is not processing master.opt input properly on Windows. *Must be done this way due to the nature of the bug* - diff --git a/mysql-test/suite/rpl/t/rpl_auto_increment_update_failure.test b/mysql-test/suite/rpl/t/rpl_auto_increment_update_failure.test new file mode 100644 index 00000000000..f38d2151ab3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_auto_increment_update_failure.test @@ -0,0 +1,214 @@ +# +# Bug45677 +# This test verifies the following two properties: +# P1) insert/update in an autoinc column causes statement to +# be logged in row format if binlog_format=mixed. +# P2) if binlog_format=mixed, and a trigger or function contains +# two or more inserts/updates in a table that has an autoinc +# column, then the slave should not go out of sync, even if +# there are concurrent transactions. +# +# Property (P1) is tested by executing an insert and an update on +# a table that has an autoinc column, and verifying that these +# statements result in row events in the binlog. +# Property (P2) is tested by setting up the test scenario and +# verifying that the tables are identical on master and slave. +# + +source include/have_binlog_format_mixed.inc; +source include/have_innodb.inc; +source include/master-slave.inc; + +--echo # Test case1: INVOKES A TRIGGER with after insert action +let $trigger_action = after insert; +source extra/rpl_tests/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case2: INVOKES A TRIGGER with before insert action +let $trigger_action = before insert; +source extra/rpl_tests/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case3: INVOKES A TRIGGER with after update action +let $trigger_action = after update; +source extra/rpl_tests/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case4: INVOKES A TRIGGER with before update action +let $trigger_action = before update; +source extra/rpl_tests/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case5: INVOKES A TRIGGER with after delete action +let $trigger_action = after delete; +source extra/rpl_tests/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case6: INVOKES A TRIGGER with before delete action +let $trigger_action = before delete; +source extra/rpl_tests/rpl_auto_increment_invoke_trigger.test; + +--echo # Test case7: CALLS A FUNCTION which INVOKES A TRIGGER with after insert action +let $insert_action = after insert; +source extra/rpl_tests/rpl_autoinc_func_invokes_trigger.test; + +--echo # Test case8: CALLS A FUNCTION which INVOKES A TRIGGER with before insert action +let $insert_action = before insert; +source extra/rpl_tests/rpl_autoinc_func_invokes_trigger.test; + +--echo # Test case9: INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS with after insert action +let $insert_action = after insert; +source extra/rpl_tests/rpl_auto_increment_insert_view.test; + +--echo # Test case10: INSERT DATA INTO VIEW WHICH INVOKES TRIGGERS with before insert action +let $insert_action = before insert; +source extra/rpl_tests/rpl_auto_increment_insert_view.test; + +--echo # Test case11: INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES INTO A TABLE WITH AUTOINC COLUMN +connection master; +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, primary key(i1)) engine=innodb; +delimiter //; +CREATE FUNCTION f1_two_inserts() RETURNS INTEGER +BEGIN + INSERT INTO t2(a) values(2); + INSERT INTO t2(a) values(2); + RETURN 1; +END// +delimiter ;// +begin; +insert into t1(a) values(f1_two_inserts()); + +connection master1; +#The default autocommit is set to 1, so the statement is auto committed +insert into t2(a) values(4),(5); + +connection master; +commit; +insert into t1(a) values(f1_two_inserts()); +commit; + +connection master; +--echo #Test result for INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES on master +select * from t2 ORDER BY i1; + +sync_slave_with_master; +connection slave; +--echo #Test result for INVOKES A FUNCTION TO INSERT TWO OR MORE VALUES on slave +select * from t2 ORDER BY i1; + +connection master; +drop table t1; +drop table t2; +drop function f1_two_inserts; +sync_slave_with_master; + +--echo # Test case12: INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES OF A TABLE WITH AUTOINC COLUMN +connection master; +create table t1(a int) engine=innodb; +create table t2(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +delimiter //; +CREATE FUNCTION f1_two_updates() RETURNS INTEGER +BEGIN + update t2 set a = a + 5 where b = 1; + update t2 set a = a + 5 where b = 2; + update t2 set a = a + 5 where b = 3; + update t2 set a = a + 5 where b = 4; + RETURN 1; +END// +delimiter ;// + +connection master1; +#The default autocommit is set to 1, so the statement is auto committed +insert into t2(a,b) values(1,1); +insert into t2(a,b) values(2,2); +insert into t2(a,b) values(3,3); +insert into t2(a,b) values(4,4); +insert into t1(a) values(f1_two_updates()); + +connection master; +begin; +insert into t1(a) values(f1_two_updates()); +commit; + +connection master; +--echo #Test result for INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES on master +select * from t2 ORDER BY i1; + +sync_slave_with_master; +connection slave; +--echo #Test result for INVOKES A FUNCTION TO UPDATE TWO OR MORE VALUES on slave +select * from t2 ORDER BY i1; + +connection master; +drop table t1; +drop table t2; +drop function f1_two_updates; +sync_slave_with_master; + +--echo # Test case13: UPDATE MORE THAN ONE TABLES ON TOP-STATEMENT +connection master; +create table t1(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +create table t2(i1 int not null auto_increment, a int, b int, primary key(i1)) engine=innodb; +begin; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +insert into t1(a,b) values(1,1),(2,2); +insert into t2(a,b) values(1,1),(2,2); +update t1,t2 set t1.a=t1.a+5, t2.a=t2.a+5 where t1.b=t2.b; +insert into t1(a,b) values(3,3); +insert into t2(a,b) values(3,3); +commit; +--echo # To verify if it works fine when these statements are not be marked as unsafe +source include/show_binlog_events.inc; + +sync_slave_with_master; +--echo #Test if the results are consistent on master and slave +--echo #for 'UPDATE MORE THAN ONE TABLES ON TOP-STATEMENT' +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; +let $diff_table_1=master:test.t2; +let $diff_table_2=slave:test.t2; +source include/diff_tables.inc; + +connection master; +drop table t1; +drop table t2; +sync_slave_with_master; + +--echo # Test case14: INSERT DATA INTO VIEW WHICH INVOLVED MORE THAN ONE TABLES +connection master; +CREATE TABLE t1(i1 int not null auto_increment, c1 INT, primary key(i1)) engine=innodb; +CREATE TABLE t2(i1 int not null auto_increment, c2 INT, primary key(i1)) engine=innodb; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +begin; +INSERT INTO t1(c1) VALUES (11), (12); +INSERT INTO t2(c2) VALUES (13), (14); + +CREATE VIEW v15 AS SELECT c1, c2 FROM t1, t2; + +INSERT INTO v15(c1) VALUES (15),(16); +INSERT INTO v15(c2) VALUES (17),(18); + +connection master1; +INSERT INTO v15(c1) VALUES (19),(20); +INSERT INTO v15(c2) VALUES (21),(22); + +connection master; +INSERT INTO v15(c1) VALUES (23), (24); +INSERT INTO v15(c2) VALUES (25), (26); +commit; +--echo # To verify if it works fine when these statements are not be marked as unsafe +source include/show_binlog_events.inc; + +sync_slave_with_master; +--echo #Test if the results are consistent on master and slave +--echo #for 'INSERT DATA INTO VIEW WHICH INVOLVED MORE THAN ONE TABLES' +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; +let $diff_table_1=master:test.t2; +let $diff_table_2=slave:test.t2; +source include/diff_tables.inc; + +connection master; +drop table t1; +drop table t2; +drop view v15; +sync_slave_with_master; + diff --git a/mysql-test/suite/rpl/t/rpl_bug33931.test b/mysql-test/suite/rpl/t/rpl_bug33931.test index 13f781c644b..1316ddb7401 100644 --- a/mysql-test/suite/rpl/t/rpl_bug33931.test +++ b/mysql-test/suite/rpl/t/rpl_bug33931.test @@ -15,7 +15,7 @@ reset master; connection slave; # Add suppression for expected warnings in slaves error log -call mtr.add_suppression("Failed during slave thread initialization"); +call mtr.add_suppression("Failed during slave I/O thread initialization"); --disable_warnings stop slave; diff --git a/mysql-test/suite/rpl/t/rpl_do_grant.test b/mysql-test/suite/rpl/t/rpl_do_grant.test index a60a4bd6c3d..38f44091b59 100644 --- a/mysql-test/suite/rpl/t/rpl_do_grant.test +++ b/mysql-test/suite/rpl/t/rpl_do_grant.test @@ -210,5 +210,10 @@ DROP FUNCTION upgrade_del_func; DROP FUNCTION upgrade_alter_func; DROP DATABASE bug42217_db; DROP USER 'create_rout_db'@'localhost'; - + +call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' Error_code: 1396"); +connection slave; +USE mtr; +call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' Error_code: 1396"); + --echo "End of test" diff --git a/mysql-test/suite/rpl/t/rpl_drop_temp.test b/mysql-test/suite/rpl/t/rpl_drop_temp.test index df162d3b244..7827e16e45f 100644 --- a/mysql-test/suite/rpl/t/rpl_drop_temp.test +++ b/mysql-test/suite/rpl/t/rpl_drop_temp.test @@ -23,6 +23,8 @@ disconnect con_temp; --source include/wait_until_disconnected.inc connection master; +-- let $wait_binlog_event= DROP +-- source include/wait_for_binlog_event.inc sync_slave_with_master; connection slave; diff --git a/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test b/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test index b9ab66165cc..e77cd308f39 100644 --- a/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test +++ b/mysql-test/suite/rpl/t/rpl_err_ignoredtable.test @@ -50,7 +50,7 @@ kill @id; drop table t2,t3; insert into t4 values (3),(4); connection master; ---error 0,1053,2013 +--error 0,1317,2013 reap; connection master1; save_master_pos; diff --git a/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock-slave.opt b/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock-slave.opt new file mode 100644 index 00000000000..f9aa8c0367e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock-slave.opt @@ -0,0 +1 @@ +--master-retry-count=60 diff --git a/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test b/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test index 40d11f2cec2..69c63eaa69f 100644 --- a/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test +++ b/mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test @@ -16,6 +16,10 @@ source include/master-slave.inc; source include/have_debug.inc; +call mtr.add_suppression("Get master clock failed with error: "); +call mtr.add_suppression("Get master SERVER_ID failed with error: "); +call mtr.add_suppression("Slave I/O: Master command COM_REGISTER_SLAVE failed: failed registering on master, reconnecting to try again"); +call mtr.add_suppression("Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids; .*"); #Test case 1: Try to get the value of the UNIX_TIMESTAMP from master under network disconnection connection slave; let $debug_saved= `select @@global.debug`; diff --git a/mysql-test/suite/rpl/t/rpl_idempotency.test b/mysql-test/suite/rpl/t/rpl_idempotency.test index bfd1860759e..c96b88a1b1a 100644 --- a/mysql-test/suite/rpl/t/rpl_idempotency.test +++ b/mysql-test/suite/rpl/t/rpl_idempotency.test @@ -8,7 +8,8 @@ connection slave; source include/have_innodb.inc; # Add suppression for expected warning(s) in slaves error log -call mtr.add_suppression("Slave: Can\'t find record in \'t1\' Error_code: 1032"); +call mtr.add_suppression("Slave: Can't find record in 't.' Error_code: 1032"); +call mtr.add_suppression("Slave: Cannot delete or update a parent row: a foreign key constraint fails .* Error_code: 1451"); call mtr.add_suppression("Slave: Cannot add or update a child row: a foreign key constraint fails .* Error_code: 1452"); SET @old_slave_exec_mode= @@global.slave_exec_mode; diff --git a/mysql-test/suite/rpl/t/rpl_init_slave_errors.test b/mysql-test/suite/rpl/t/rpl_init_slave_errors.test index 4ca0de6ec66..180821730ec 100644 --- a/mysql-test/suite/rpl/t/rpl_init_slave_errors.test +++ b/mysql-test/suite/rpl/t/rpl_init_slave_errors.test @@ -57,6 +57,7 @@ source include/wait_for_slave_to_stop.inc; let $error= query_get_value(SHOW SLAVE STATUS, Last_Error, 1); echo Reporting the following error: $error; +call mtr.add_suppression("Failed during slave I/O thread initialization"); SET GLOBAL debug= ""; diff --git a/mysql-test/suite/rpl/t/rpl_loaddatalocal.test b/mysql-test/suite/rpl/t/rpl_loaddatalocal.test index 23c802ab3de..a93a82d6d9f 100644 --- a/mysql-test/suite/rpl/t/rpl_loaddatalocal.test +++ b/mysql-test/suite/rpl/t/rpl_loaddatalocal.test @@ -98,3 +98,73 @@ DROP TABLE t1; --echo [on slave] sync_slave_with_master; +--echo +--echo Bug #43746: +--echo "return wrong query string when parse 'load data infile' sql statement" +--echo + +--echo [master] +connection master; +let $MYSQLD_DATADIR= `select @@datadir`; +SELECT @@SESSION.sql_mode INTO @old_mode; + +SET sql_mode='ignore_space'; + +CREATE TABLE t1(a int); +INSERT INTO t1 VALUES (1), (2), (3), (4); + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval SELECT * INTO OUTFILE '$MYSQLD_DATADIR/bug43746.sql' FROM t1; +TRUNCATE TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD/* look mum, with comments in weird places! */DATA/* oh hai */LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql'/* we are */INTO/* from the internets */TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA/*!10000 LOCAL */INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' /*!10000 INTO */ TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' /*!10000 INTO TABLE */ t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA /*!10000 LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO TABLE */ t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA/*!10000 LOCAL */INFILE '$MYSQLD_DATADIR/bug43746.sql'/*!10000 INTO*/TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA/*!10000 LOCAL */INFILE '$MYSQLD_DATADIR/bug43746.sql'/* empty */INTO TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA/*!10000 LOCAL */INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO/* empty */TABLE t1; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD/*!99999 special comments that do not expand */DATA/*!99999 code from the future */LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql'/*!99999 have flux capacitor */INTO/*!99999 will travel */TABLE t1; + +SET sql_mode='PIPES_AS_CONCAT,ANSI_QUOTES,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,TRADITIONAL,NO_AUTO_CREATE_USER'; + +--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR +eval LOAD DATA LOCAL INFILE '$MYSQLD_DATADIR/bug43746.sql' INTO TABLE t1; + +--echo [slave] +sync_slave_with_master; + +# cleanup + +--remove_file $MYSQLD_DATADIR/bug43746.sql + +--echo [master] +connection master; +DROP TABLE t1; +SET SESSION sql_mode=@old_mode; + +--echo [slave] +sync_slave_with_master; + +connection master; diff --git a/mysql-test/suite/rpl/t/rpl_log_pos.test b/mysql-test/suite/rpl/t/rpl_log_pos.test index 5e8390f97ed..48effa00b64 100644 --- a/mysql-test/suite/rpl/t/rpl_log_pos.test +++ b/mysql-test/suite/rpl/t/rpl_log_pos.test @@ -11,6 +11,7 @@ # Passes with rbr no problem, removed statement include [jbm] source include/master-slave.inc; +call mtr.add_suppression ("Slave I/O: Got fatal error 1236 from master when reading data from binary"); source include/show_master_status.inc; sync_slave_with_master; source include/stop_slave.inc; diff --git a/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test b/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test new file mode 100644 index 00000000000..bf5c6d2b921 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mysql_upgrade.test @@ -0,0 +1,56 @@ +############################################################################# +# BUG#43579 mysql_upgrade tries to alter log tables on replicated database +# Master and slave should be upgraded separately. All statements executed by +# mysql_upgrade will not be binlogged. --write-binlog and --skip-write-binlog +# options are added into mysql_upgrade. These options control whether sql +# statements are binlogged or not. +############################################################################# +--source include/master-slave.inc + +# Only run test if "mysql_upgrade" is found +--source include/have_mysql_upgrade.inc + +connection master; +--disable_warnings +DROP DATABASE IF EXISTS `#mysql50#mysqltest-1`; +CREATE DATABASE `#mysql50#mysqltest-1`; +--enable_warnings +sync_slave_with_master; + +connection master; +let $before_position= query_get_value(SHOW MASTER STATUS, Position, 1); + +#With '--force' option, mysql_upgrade always executes all sql statements for upgrading. +#--skip-write-binlog option disables binlog. +--exec $MYSQL_UPGRADE --skip-write-binlog --skip-verbose --force --user=root > $MYSQLTEST_VARDIR/log/mysql_upgrade.log 2>&1 +sync_slave_with_master; + +connection master; +let $after_position= query_get_value(SHOW MASTER STATUS, Position, 1); + +if (`SELECT '$before_position'='$after_position'`) +{ + echo Master position is not changed; +} + +#Some log events of the mysql_upgrade's will cause errors on slave. +connection slave; +STOP SLAVE SQL_THREAD; +source include/wait_for_slave_sql_to_stop.inc; + +connection master; +#With '--force' option, mysql_upgrade always executes all sql statements for upgrading. +--exec $MYSQL_UPGRADE --skip-verbose --force --user=root > $MYSQLTEST_VARDIR/log/mysql_upgrade.log 2>&1 + +connection master; +let $after_file= query_get_value(SHOW MASTER STATUS, File, 1); +let $after_position= query_get_value(SHOW MASTER STATUS, Position, 1); + +if (!`SELECT '$before_position'='$after_position'`) +{ + echo Master position has been changed; +} + +DROP DATABASE `mysqltest-1`; +connection slave; +DROP DATABASE `#mysql50#mysqltest-1`; diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index 79cb2d9d735..bfc144c759b 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -5,6 +5,9 @@ # max-out size db name source include/master-slave.inc; +source include/have_binlog_format_row.inc; +call mtr.add_suppression("Slave I/O: Got a packet bigger than 'max_allowed_packet' bytes, Error_code: 1153"); +call mtr.add_suppression("Slave I/O: Got fatal error 1236 from master when reading data from binary log:"); let $db= DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________; disable_warnings; @@ -86,6 +89,35 @@ connection slave; --source include/wait_for_slave_io_to_stop.inc let $slave_io_running= query_get_value(SHOW SLAVE STATUS, Slave_IO_Running, 1); --echo Slave_IO_Running = $slave_io_running (expect No) +# +# Bug#42914: The slave I/O thread must stop after trying to read the above +# event, However there is no Last_IO_Error report. +# +let $last_io_error= query_get_value(SHOW SLAVE STATUS, Last_IO_Error, 1); +eval SELECT "$last_io_error" AS Last_IO_Error; + +# +# Bug#42914: On the master, if a binary log event is larger than +# max_allowed_packet, the error message ER_MASTER_FATAL_ERROR_READING_BINLOG +# is sent to a slave when it requests a dump from the master, thus leading the +# I/O thread to stop. However, there is no Last_IO_Error reported. +# +source include/master-slave-reset.inc; +connection master; +CREATE TABLE t1 (f1 int PRIMARY KEY, f2 LONGTEXT, f3 LONGTEXT) ENGINE=MyISAM; +sync_slave_with_master; + +connection master; +INSERT INTO t1(f1, f2, f3) VALUES(1, REPEAT('a', @@global.max_allowed_packet), REPEAT('b', @@global.max_allowed_packet)); + +connection slave; +# The slave I/O thread must stop after receiving +# ER_MASTER_FATAL_ERROR_READING_BINLOG error message from master. +--source include/wait_for_slave_io_to_stop.inc +let $slave_io_running= query_get_value(SHOW SLAVE STATUS, Slave_IO_Running, 1); +--echo Slave_IO_Running = $slave_io_running (expect No) +let $last_io_error= query_get_value(SHOW SLAVE STATUS, Last_IO_Error, 1); +eval SELECT "$last_io_error" AS Last_IO_Error; --echo ==== clean up ==== connection master; diff --git a/mysql-test/suite/rpl/t/rpl_row_disabled_slave_key.test b/mysql-test/suite/rpl/t/rpl_row_disabled_slave_key.test new file mode 100644 index 00000000000..1d7e134f4f4 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_disabled_slave_key.test @@ -0,0 +1,73 @@ +# BUG#47312: RBR: Disabling key on slave breaks replication: +# HA_ERR_WRONG_INDEX +# +# Description +# =========== +# +# This test case checks whether disabling a key on a slave breaks +# replication or not. +# +# Case #1, shows that while not using ALTER TABLE... DISABLE KEYS and +# the slave has no key defined while the master has one, replication +# won't break. +# +# Case #2, shows that before patch for BUG#47312, if defining key on +# slave table, and later disable it, replication would break. This +# has been fixed. +# + +-- source include/master-slave.inc +-- source include/have_binlog_format_row.inc + +# +# Case #1: master has key, but slave has not. +# Replication does not break. +# + +SET SQL_LOG_BIN=0; +CREATE TABLE t (a int, b int, c int, key(b)); +SET SQL_LOG_BIN=1; + +-- connection slave + +CREATE TABLE t (a int, b int, c int); + +-- connection master + +INSERT INTO t VALUES (1,2,4); +INSERT INTO t VALUES (4,3,4); +DELETE FROM t; + +-- sync_slave_with_master + +-- connection master +DROP TABLE t; + +-- sync_slave_with_master + +# +# Case #2: master has key, slave also has one, +# but it gets disabled sometime. +# Replication does not break anymore. +# +-- source include/master-slave-reset.inc +-- connection master + +CREATE TABLE t (a int, b int, c int, key(b)); + +-- sync_slave_with_master + +ALTER TABLE t DISABLE KEYS; + +-- connection master + +INSERT INTO t VALUES (1,2,4); +INSERT INTO t VALUES (4,3,4); +DELETE FROM t; + +-- sync_slave_with_master + +-- connection master +DROP TABLE t; + +-- sync_slave_with_master diff --git a/mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test b/mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test index 39f3b700f94..437e1ebb92d 100644 --- a/mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test +++ b/mysql-test/suite/rpl/t/rpl_slave_load_remove_tmpfile.test @@ -7,6 +7,7 @@ # 1 - Creates a table and populates it through "LOAD DATA INFILE". # 2 - Catches error. ########################################################################## + --source include/have_binlog_format_mixed_or_statement.inc --source include/have_innodb.inc --source include/have_debug.inc @@ -47,3 +48,5 @@ drop table t1; connection slave; drop table t1; + +call mtr.add_suppression("Slave: Error writing file 'UNKNOWN' .Errcode: 9. Error_code: 3"); diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result index 01f8d94da48..b6f32668c42 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_circular_simplex.result @@ -102,3 +102,4 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 0 Last_SQL_Error +DROP TABLE t1; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result index d51599fd18b..f812509de6f 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result @@ -4,6 +4,7 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +call mtr.add_suppression("Slave: Unknown table 't6' Error_code: 1051"); **** Diff Table Def Start **** *** On Slave *** STOP SLAVE; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_sp006.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_sp006.result index 482d43c8f10..047402f826f 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_sp006.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_sp006.result @@ -4,21 +4,20 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -create database if not exists mysqltest1; -DROP PROCEDURE IF EXISTS mysqltest1.p1; -DROP PROCEDURE IF EXISTS mysqltest1.p2; -DROP TABLE IF EXISTS mysqltest1.t2; -DROP TABLE IF EXISTS mysqltest1.t1; -CREATE TABLE IF NOT EXISTS mysqltest1.t1(name CHAR(16), birth DATE,PRIMARY KEY(name))ENGINE=NDBCLUSTER; -CREATE TABLE IF NOT EXISTS mysqltest1.t2(name CHAR(16), age INT ,PRIMARY KEY(name))ENGINE=NDBCLUSTER; -CREATE PROCEDURE mysqltest1.p1() +DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t2; +DROP PROCEDURE IF EXISTS p1; +DROP PROCEDURE IF EXISTS p2; +CREATE TABLE IF NOT EXISTS t1(name CHAR(16), birth DATE,PRIMARY KEY(name))ENGINE=NDBCLUSTER; +CREATE TABLE IF NOT EXISTS t2(name CHAR(16), age INT ,PRIMARY KEY(name))ENGINE=NDBCLUSTER; +CREATE PROCEDURE p1() BEGIN DECLARE done INT DEFAULT 0; DECLARE spa CHAR(16); DECLARE spb INT; DECLARE cur1 CURSOR FOR SELECT name, (YEAR(CURDATE())-YEAR(birth))-(RIGHT(CURDATE(),5)<RIGHT(birth,5)) -FROM mysqltest1.t1; +FROM t1; DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; OPEN cur1; SET AUTOCOMMIT=0; @@ -26,21 +25,20 @@ REPEAT FETCH cur1 INTO spa, spb; IF NOT done THEN START TRANSACTION; -INSERT INTO mysqltest1.t2 VALUES (spa,spb); +INSERT INTO t2 VALUES (spa,spb); COMMIT; END IF; UNTIL done END REPEAT; SET AUTOCOMMIT=1; CLOSE cur1; END| -CREATE PROCEDURE mysqltest1.p2() +CREATE PROCEDURE p2() BEGIN -INSERT INTO mysqltest1.t1 VALUES ('MySQL','1993-02-04'),('ROCKS', '1990-08-27'),('Texas', '1999-03-30'),('kyle','2005-1-1'); +INSERT INTO t1 VALUES ('MySQL','1993-02-04'),('ROCKS', '1990-08-27'),('Texas', '1999-03-30'),('kyle','2005-1-1'); END| -CALL mysqltest1.p2(); -CALL mysqltest1.p1(); -DROP PROCEDURE IF EXISTS mysqltest1.p1; -DROP PROCEDURE IF EXISTS mysqltest1.p2; -DROP TABLE IF EXISTS mysqltest1.t1; -DROP TABLE IF EXISTS mysqltest1.t2; -DROP DATABASE mysqltest1; +CALL p2(); +CALL p1(); +DROP TABLE t1; +DROP TABLE t2; +DROP PROCEDURE p1; +DROP PROCEDURE p2; diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test index 2cc46e2420e..7b8497d8dab 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular.test @@ -58,3 +58,4 @@ STOP SLAVE; # cleanup --connection master DROP TABLE t1; +-- sync_slave_with_master diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_simplex.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_simplex.test index d5ddfc2b739..eb04dc2e260 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_simplex.test +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_simplex.test @@ -78,3 +78,7 @@ SELECT * FROM t1 ORDER BY a; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 # 35 # 36 # query_vertical SHOW SLAVE STATUS; + +-- connection master +DROP TABLE t1; +-- sync_slave_with_master diff --git a/mysql-test/t/almost_full.test b/mysql-test/t/almost_full.test index c192a7c1cd4..2517008fdf8 100644 --- a/mysql-test/t/almost_full.test +++ b/mysql-test/t/almost_full.test @@ -2,6 +2,8 @@ # Some special cases with empty tables # +call mtr.add_suppression("The table 't1' is full"); + --disable_warnings drop table if exists t1; --enable_warnings diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index efda5fc1893..98ae90ce13c 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -1027,5 +1027,65 @@ INSERT INTO t1 (a) VALUES (11); SELECT * FROM t1 ORDER BY a; DROP TABLE t1; SET @@sql_mode=@save_sql_mode; +--echo # +--echo # Bug#45567: Fast ALTER TABLE broken for enum and set +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (a ENUM('a1','a2')); +INSERT INTO t1 VALUES ('a1'),('a2'); +--enable_info +--echo # No copy: No modification +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2'); +--echo # No copy: Add new enumeration to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a3'); +--echo # Copy: Modify and add new to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','xx','a5'); +--echo # Copy: Remove from the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','xx'); +--echo # Copy: Add new enumeration +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a0','xx'); +--echo # No copy: Add new enumerations to the end +ALTER TABLE t1 MODIFY COLUMN a ENUM('a1','a2','a0','xx','a5','a6'); +--disable_info +DROP TABLE t1; + +CREATE TABLE t1 (a SET('a1','a2')); +INSERT INTO t1 VALUES ('a1'),('a2'); +--enable_info +--echo # No copy: No modification +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2'); +--echo # No copy: Add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a3'); +--echo # Copy: Modify and add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','xx','a5'); +--echo # Copy: Remove from the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','xx'); +--echo # Copy: Add new member +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx'); +--echo # No copy: Add new to the end +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx','a5','a6'); +--echo # Copy: Numerical incrase (pack lenght) +ALTER TABLE t1 MODIFY COLUMN a SET('a1','a2','a0','xx','a5','a6','a7','a8','a9','a10'); +--disable_info +DROP TABLE t1; + +# +# Bug#43508: Renaming timestamp or date column triggers table copy +# + +CREATE TABLE t1 (f1 TIMESTAMP NULL DEFAULT NULL, + f2 INT(11) DEFAULT NULL) ENGINE=MYISAM DEFAULT CHARSET=utf8; + +INSERT INTO t1 VALUES (NULL, NULL), ("2009-10-09 11:46:19", 2); + +--echo this should affect no rows as there is no real change +--enable_info +ALTER TABLE t1 CHANGE COLUMN f1 f1_no_real_change TIMESTAMP NULL DEFAULT NULL; +--disable_info +DROP TABLE t1; --echo End of 5.1 tests diff --git a/mysql-test/t/analyse.test b/mysql-test/t/analyse.test index d8466df14bf..05f739bfd69 100644 --- a/mysql-test/t/analyse.test +++ b/mysql-test/t/analyse.test @@ -10,37 +10,14 @@ insert into t1 values (1,2,"","Y","2002-03-03"), (3,4,"","N","2002-03-04"), (5,6 select count(*) from t1 procedure analyse(); select * from t1 procedure analyse(); select * from t1 procedure analyse(2); +--error ER_WRONG_USAGE create table t2 select * from t1 procedure analyse(); -select * from t2; -drop table t1,t2; +drop table t1; --error ER_WRONG_USAGE EXPLAIN SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(); # -# Test with impossible where -# -create table t1 (a int not null); -create table t2 select * from t1 where 0=1 procedure analyse(); -show create table t2; -select * from t1 where 0=1 procedure analyse(); -insert into t1 values(1); -drop table t2; -create table t2 select * from t1 where 0=1 procedure analyse(); -show create table t2; -select * from t2; -insert into t2 select * from t1 procedure analyse(); -select * from t2; -insert into t1 values(2); -drop table t2; -create table t2 select * from t1 where 0=1 procedure analyse(); -show create table t2; -select * from t2; -insert into t2 select * from t1 procedure analyse(); -select * from t2; -drop table t1,t2; - -# # Bug#2813 - analyse does not quote string values in enums from string # @@ -113,3 +90,46 @@ SELECT * FROM (SELECT * FROM t1) d PROCEDURE ANALYSE(); DROP TABLE t1; --echo End of 4.1 tests + +--echo # +--echo # Bug #48293: crash with procedure analyse, view with > 10 columns, +--echo # having clause... +--echo # + +CREATE TABLE t1(a INT, b INT, c INT, d INT, e INT, + f INT, g INT, h INT, i INT, j INT,k INT); +INSERT INTO t1 VALUES (),(); + +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +--echo #should have a derived table +EXPLAIN SELECT * FROM v1; +--echo #should not crash +--error ER_WRONG_USAGE +SELECT * FROM v1 PROCEDURE analyse(); +--echo #should not crash +--error ER_WRONG_USAGE +SELECT * FROM t1 a, v1, t1 b PROCEDURE analyse(); +--echo #should not crash +--error ER_WRONG_USAGE +SELECT * FROM (SELECT * FROM t1 having a > 1) x PROCEDURE analyse(); +--echo #should not crash +--error ER_WRONG_USAGE +SELECT * FROM t1 a, (SELECT * FROM t1 having a > 1) x, t1 b PROCEDURE analyse(); +--echo #should not crash +--error ER_ORDER_WITH_PROC +SELECT 1 FROM t1 group by a having a > 1 order by 1 PROCEDURE analyse(); + +DROP VIEW v1; +DROP TABLE t1; + +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1),(2); + +--echo # should not crash +--error ER_WRONG_USAGE +CREATE TABLE t2 SELECT 1 FROM t1, t1 t3 GROUP BY t3.a PROCEDURE ANALYSE(); + +DROP TABLE t1; + + +--echo End of 5.0 tests diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index 5864e539b08..9f67547f729 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1601,3 +1601,27 @@ INSERT INTO t1 VALUES (NULL, NULL),(NULL, NULL); FLUSH TABLE t1; SELECT * FROM t1 ORDER BY a; DROP TABLE t1; + +# +# BUG#29203 - archive tables have weird values in show table status +# +CREATE TABLE t1(a INT, b BLOB) ENGINE=archive; +SELECT DATA_LENGTH, AVG_ROW_LENGTH FROM + INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test'; +INSERT INTO t1 VALUES(1, 'sampleblob1'),(2, 'sampleblob2'); +SELECT DATA_LENGTH, AVG_ROW_LENGTH FROM + INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test'; +DROP TABLE t1; + +# +# BUG#46961 - archive engine loses rows during self joining select! +# +SET @save_join_buffer_size= @@join_buffer_size; +SET @@join_buffer_size= 8228; +CREATE TABLE t1(a CHAR(255)) ENGINE=archive; +INSERT INTO t1 VALUES('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'), + ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'), + ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); +SELECT COUNT(t1.a) FROM t1, t1 a, t1 b, t1 c, t1 d, t1 e; +DROP TABLE t1; +SET @@join_buffer_size= @save_join_buffer_size; diff --git a/mysql-test/t/bug40113.test b/mysql-test/t/bug40113.test deleted file mode 100644 index 6d35d0b73d3..00000000000 --- a/mysql-test/t/bug40113.test +++ /dev/null @@ -1,46 +0,0 @@ ---source include/have_innodb.inc - ---echo # ---echo # Bug #40113: Embedded SELECT inside UPDATE or DELETE can timeout ---echo # without error ---echo # - -CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b)) ENGINE=InnoDB; - -INSERT INTO t1 (a,b) VALUES (1070109,99); - -CREATE TABLE t2 (b int, a int, PRIMARY KEY (b)) ENGINE=InnoDB; - -INSERT INTO t2 (b,a) VALUES (7,1070109); - -SELECT * FROM t1; - -BEGIN; - -SELECT b FROM t2 WHERE b=7 FOR UPDATE; - -CONNECT (addconroot, localhost, root,,); -CONNECTION addconroot; - -BEGIN; - ---error ER_LOCK_WAIT_TIMEOUT -SELECT b FROM t2 WHERE b=7 FOR UPDATE; - ---error ER_LOCK_WAIT_TIMEOUT -INSERT INTO t1 (a) VALUES ((SELECT a FROM t2 WHERE b=7)); - ---error ER_LOCK_WAIT_TIMEOUT -UPDATE t1 SET a='7000000' WHERE a=(SELECT a FROM t2 WHERE b=7); - ---error ER_LOCK_WAIT_TIMEOUT -DELETE FROM t1 WHERE a=(SELECT a FROM t2 WHERE b=7); - -SELECT * FROM t1; - -CONNECTION default; -DISCONNECT addconroot; - -DROP TABLE t2, t1; - ---echo End of 5.0 tests diff --git a/mysql-test/t/bug46080.test b/mysql-test/t/bug46080.test index 7e56e3ce421..8b4cee4d8b0 100644 --- a/mysql-test/t/bug46080.test +++ b/mysql-test/t/bug46080.test @@ -3,6 +3,9 @@ --echo # sort_buffer_size cannot allocate --echo # +call mtr.add_suppression("Out of memory at line .*, 'my_alloc.c'"); +call mtr.add_suppression("needed .* byte .*k., memory in use: .* bytes .*k"); + CREATE TABLE t1(a CHAR(255)); INSERT INTO t1 VALUES ('a'); diff --git a/mysql-test/t/bug46760-master.opt b/mysql-test/t/bug46760-master.opt new file mode 100644 index 00000000000..f830d135149 --- /dev/null +++ b/mysql-test/t/bug46760-master.opt @@ -0,0 +1,2 @@ +--innodb-lock-wait-timeout=2 +--innodb-file-per-table diff --git a/mysql-test/t/bug46760.test b/mysql-test/t/bug46760.test new file mode 100644 index 00000000000..f55edbbfa42 --- /dev/null +++ b/mysql-test/t/bug46760.test @@ -0,0 +1,38 @@ +-- source include/have_innodb.inc + +--echo # +--echo # Bug#46760: Fast ALTER TABLE no longer works for InnoDB +--echo # + +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); + +--echo # By using --enable_info and verifying that number of affected +--echo # rows is 0 we check that this ALTER TABLE is really carried +--echo # out as "fast/online" operation, i.e. without full-blown data +--echo # copying. +--echo # +--echo # I.e. info for the below statement should normally look like: +--echo # +--echo # affected rows: 0 +--echo # info: Records: 0 Duplicates: 0 Warnings: 0 + +--enable_info +ALTER TABLE t1 ALTER COLUMN a SET DEFAULT 10; +--disable_info +SHOW CREATE TABLE t1; + +DROP TABLE t1; + +--echo # +--echo # MySQL Bug#39200: optimize table does not recognize +--echo # ROW_FORMAT=COMPRESSED +--echo # + +CREATE TABLE t1 (a INT) ROW_FORMAT=compressed; +SHOW CREATE TABLE t1; +OPTIMIZE TABLE t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--echo End of 5.1 tests diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 63968caed94..885803cb90f 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -1198,6 +1198,23 @@ CREATE TABLE IF NOT EXISTS t2 (a INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY) DROP TABLE t1, t2; +--echo # +--echo # BUG#46384 - mysqld segfault when trying to create table with same +--echo # name as existing view +--echo # + +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); + +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t2 VALUES (1),(2),(3); + +CREATE VIEW v1 AS SELECT t1.a FROM t1, t2; +--error ER_TABLE_EXISTS_ERROR +CREATE TABLE v1 AS SELECT * FROM t1; + +DROP VIEW v1; +DROP TABLE t1,t2; --echo End of 5.0 tests diff --git a/mysql-test/t/ctype_ldml.test b/mysql-test/t/ctype_ldml.test index db9461bfbf7..0395de273de 100644 --- a/mysql-test/t/ctype_ldml.test +++ b/mysql-test/t/ctype_ldml.test @@ -38,6 +38,14 @@ SELECT * FROM t1 WHERE col1=col2 ORDER BY col1; DROP TABLE t1; --echo # +--echo # Bug#45645 Mysql server close all connection and restart using lower function +--echo # +CREATE TABLE t1 (a VARCHAR(10)) CHARACTER SET utf8 COLLATE utf8_test_ci; +INSERT INTO t1 (a) VALUES ('hello!'); +SELECT * FROM t1 WHERE LOWER(a)=LOWER('N'); +DROP TABLE t1; + +--echo # --echo # Bug#43827 Server closes connections and restarts --echo # # Crash happened with a user-defined utf8 collation, @@ -86,3 +94,8 @@ select hex(c1) as h, c1 from t1 order by c1, h; select group_concat(hex(c1) order by hex(c1)) from t1 group by c1; select group_concat(c1 order by hex(c1) SEPARATOR '') from t1 group by c1; drop table t1; + +--echo Bug#46448 trailing spaces are not ignored when user collation maps space != 0x20 +set names latin1; +show collation like 'latin1_test'; +select "foo" = "foo " collate latin1_test; diff --git a/mysql-test/t/debug_sync.test b/mysql-test/t/debug_sync.test new file mode 100644 index 00000000000..514e471b603 --- /dev/null +++ b/mysql-test/t/debug_sync.test @@ -0,0 +1,420 @@ +###################### t/debug_sync.test ############################### +# # +# Testing of the Debug Sync Facility. # +# # +# There is important documentation within sql/debug_sync.cc # +# # +# Used objects in this test case: # +# p0 - synchronization point 0. Non-existent dummy sync point. # +# s1 - signal 1. # +# s2 - signal 2. # +# # +# Creation: # +# 2008-02-18 istruewing # +# # +######################################################################## + +# +# We need the Debug Sync Facility. +# +--source include/have_debug_sync.inc + +# +# We are checking privileges, which the embedded server cannot do. +# +--source include/not_embedded.inc + +# +# Preparative cleanup. +# +--disable_warnings +SET DEBUG_SYNC= 'RESET'; +DROP TABLE IF EXISTS t1; +--enable_warnings + +# +# Show the special system variable. +# It shows ON or OFF depending on the command line option --debug-sync. +# The test case assumes it is ON (command line option present). +# +SHOW VARIABLES LIKE 'DEBUG_SYNC'; + +# +# Syntax. Valid forms. +# +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 EXECUTE 2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE 2'; +SET DEBUG_SYNC='p0 SIGNAL s1 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 SIGNAL s1'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 EXECUTE 2'; +SET DEBUG_SYNC='p0 WAIT_FOR s2 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 HIT_LIMIT 3'; +SET DEBUG_SYNC='p0 CLEAR'; +SET DEBUG_SYNC='p0 TEST'; +SET DEBUG_SYNC='RESET'; + +# +# Syntax. Valid forms. Lower case. +# +set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6 execute 2'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2 timeout 6'; +set debug_sync='p0 signal s1 wait_for s2 execute 2 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2 execute 2'; +set debug_sync='p0 signal s1 wait_for s2 hit_limit 3'; +set debug_sync='p0 signal s1 wait_for s2'; +set debug_sync='p0 signal s1 execute 2 hit_limit 3'; +set debug_sync='p0 signal s1 execute 2'; +set debug_sync='p0 signal s1 hit_limit 3'; +set debug_sync='p0 signal s1'; +set debug_sync='p0 wait_for s2 timeout 6 execute 2 hit_limit 3'; +set debug_sync='p0 wait_for s2 timeout 6 execute 2'; +set debug_sync='p0 wait_for s2 timeout 6 hit_limit 3'; +set debug_sync='p0 wait_for s2 timeout 6'; +set debug_sync='p0 wait_for s2 execute 2 hit_limit 3'; +set debug_sync='p0 wait_for s2 execute 2'; +set debug_sync='p0 wait_for s2 hit_limit 3'; +set debug_sync='p0 wait_for s2'; +set debug_sync='p0 hit_limit 3'; +set debug_sync='p0 clear'; +set debug_sync='p0 test'; +set debug_sync='reset'; + +# +# Syntax. Valid forms. Line wrap, leading, mid, trailing space. +# +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 + EXECUTE 2 HIT_LIMIT 3'; +SET DEBUG_SYNC=' p0 SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2'; +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 '; +SET DEBUG_SYNC=' p0 SIGNAL s1 WAIT_FOR s2 '; +SET DEBUG_SYNC=' p0 SIGNAL s1 WAIT_FOR s2 '; + +# +# Syntax. Invalid forms. +# +--error ER_PARSE_ERROR +SET DEBUG_SYNC=''; +--error ER_PARSE_ERROR +SET DEBUG_SYNC=' '; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TIMEOUT 6 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TIMEOUT 6'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 SIGNAL s1 TIMEOUT 6'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 SIGNAL s1'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TIMEOUT 6 WAIT_FOR s2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 TIMEOUT 6 EXECUTE 2'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 TIMEOUT 6'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 EXECUTE 2 SIGNAL s1 TIMEOUT 6'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TIMEOUT 6 SIGNAL s1'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 EXECUTE 2 TIMEOUT 6 SIGNAL s1'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 CLEAR HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='CLEAR'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 CLEAR p0'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='TEST'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TEST p0'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 RESET'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='RESET p0'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 RESET p0'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL '; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR '; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 EXECUTE '; + +# +# Syntax. Invalid keywords used. +# +--error ER_UNKNOWN_SYSTEM_VARIABLE +SET DEBUG_SYNCx='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAx s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOx s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUx 0 EXECUTE 2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTx 2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 SIGNAL s1 WAIT_FOR s2 TIMEOUT 6 EXECUTE 2 HIT_LIMIx 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 CLEARx'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 TESTx'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='RESETx'; + +# +# Syntax. Invalid numbers. Decimal only. +# +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 0x6 EXECUTE 2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 6 EXECUTE 0x2 HIT_LIMIT 3'; +--error ER_PARSE_ERROR +SET DEBUG_SYNC='p0 WAIT_FOR s2 TIMEOUT 7 EXECUTE 2 HIT_LIMIT 0x3'; + +# +# Syntax. Invalid value type. +# +--error ER_WRONG_TYPE_FOR_VAR +SET DEBUG_SYNC= 7; + +# +# Syntax. DEBUG_SYNC is a SESSION-only variable. +# +--error ER_LOCAL_VARIABLE +SET GLOBAL DEBUG_SYNC= 'p0 CLEAR'; + +# +# Syntax. The variable value does not need to be a string literal. +# +SET @myvar= 'now SIGNAL from_myvar'; +SET DEBUG_SYNC= @myvar; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +# +SET DEBUG_SYNC= LEFT('now SIGNAL from_function_cut_here', 24); +SHOW VARIABLES LIKE 'DEBUG_SYNC'; + +# +# Functional tests. +# +# NOTE: There is the special synchronization point 'now'. It is placed +# immediately after setting of the DEBUG_SYNC variable. +# So it is executed before the SET statement ends. +# +# NOTE: There is only one global signal (say "signal post" or "flag mast"). +# A SIGNAL action writes its signal into it ("sets a flag"). +# The signal persists until explicitly overwritten. +# To avoid confusion for later tests, it is recommended to clear +# the signal by signalling "empty" ("setting the 'empty' flag"): +# SET DEBUG_SYNC= 'now SIGNAL empty'; +# Preferably you can reset the whole facility with: +# SET DEBUG_SYNC= 'RESET'; +# The signal is then '' (really empty) which connot be done otherwise. +# + +# +# Time out immediately. This gives just a warning. +# +SET DEBUG_SYNC= 'now SIGNAL something'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +# Suppress warning number +--replace_column 2 #### +SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0'; +# +# If signal is present already, TIMEOUT 0 does not give a warning. +# +SET DEBUG_SYNC= 'now SIGNAL nothing'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'now WAIT_FOR nothing TIMEOUT 0'; + +# +# EXECUTE 0 is effectively a no-op. +# +SET DEBUG_SYNC= 'now SIGNAL something EXECUTE 0'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'now WAIT_FOR anotherthing TIMEOUT 0 EXECUTE 0'; + +# +# Run into HIT_LIMIT. This gives an error. +# +--error ER_DEBUG_SYNC_HIT_LIMIT +SET DEBUG_SYNC= 'now HIT_LIMIT 1'; + +# +# Many actions. Watch the array growing and shrinking in the debug trace: +# egrep 'query:|debug_sync_action:' mysql-test/var/log/master.trace +# +SET DEBUG_SYNC= 'RESET'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p1abcd SIGNAL s1 EXECUTE 2'; +SET DEBUG_SYNC= 'p2abc SIGNAL s2 EXECUTE 2'; +SET DEBUG_SYNC= 'p9abcdef SIGNAL s9 EXECUTE 2'; +SET DEBUG_SYNC= 'p4a SIGNAL s4 EXECUTE 2'; +SET DEBUG_SYNC= 'p5abcde SIGNAL s5 EXECUTE 2'; +SET DEBUG_SYNC= 'p6ab SIGNAL s6 EXECUTE 2'; +SET DEBUG_SYNC= 'p7 SIGNAL s7 EXECUTE 2'; +SET DEBUG_SYNC= 'p8abcdef SIGNAL s8 EXECUTE 2'; +SET DEBUG_SYNC= 'p3abcdef SIGNAL s3 EXECUTE 2'; +# +# Execute some actions to show they exist. Each sets a distinct signal. +# +SET DEBUG_SYNC= 'p4a TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p1abcd TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p7 TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p9abcdef TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p3abcdef TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +# +# Clear the actions. +# +SET DEBUG_SYNC= 'p1abcd CLEAR'; +SET DEBUG_SYNC= 'p2abc CLEAR'; +SET DEBUG_SYNC= 'p5abcde CLEAR'; +SET DEBUG_SYNC= 'p6ab CLEAR'; +SET DEBUG_SYNC= 'p8abcdef CLEAR'; +SET DEBUG_SYNC= 'p9abcdef CLEAR'; +SET DEBUG_SYNC= 'p3abcdef CLEAR'; +SET DEBUG_SYNC= 'p4a CLEAR'; +SET DEBUG_SYNC= 'p7 CLEAR'; +# +# Execute some actions to show they have gone. +# +SET DEBUG_SYNC= 'p1abcd TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p7 TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +SET DEBUG_SYNC= 'p9abcdef TEST'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; +# +# Now cleanup. Actions are clear already, but signal needs to be cleared. +# +SET DEBUG_SYNC= 'RESET'; +SHOW VARIABLES LIKE 'DEBUG_SYNC'; + +# +# Facility requires SUPER privilege. +# +CREATE USER mysqltest_1@localhost; +GRANT SUPER ON *.* TO mysqltest_1@localhost; +--echo connection con1, mysqltest_1 +connect (con1,localhost,mysqltest_1,,); +SET DEBUG_SYNC= 'RESET'; +disconnect con1; +--echo connection default +connection default; +DROP USER mysqltest_1@localhost; +# +CREATE USER mysqltest_2@localhost; +GRANT ALL ON *.* TO mysqltest_2@localhost; +REVOKE SUPER ON *.* FROM mysqltest_2@localhost; +--echo connection con1, mysqltest_2 +connect (con1,localhost,mysqltest_2,,); +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +SET DEBUG_SYNC= 'RESET'; +disconnect con1; +--echo connection default +connection default; +DROP USER mysqltest_2@localhost; + +# +# Example 1. +# +# Preparative cleanup. +--disable_warnings +SET DEBUG_SYNC= 'RESET'; +DROP TABLE IF EXISTS t1; +--enable_warnings +# +# Test. +CREATE TABLE t1 (c1 INT); + --echo connection con1 + connect (con1,localhost,root,,); + SET DEBUG_SYNC= 'before_lock_tables_takes_lock + SIGNAL opened WAIT_FOR flushed'; + send INSERT INTO t1 VALUES(1); +--echo connection default +connection default; +SET DEBUG_SYNC= 'now WAIT_FOR opened'; +SET DEBUG_SYNC= 'after_flush_unlock SIGNAL flushed'; +FLUSH TABLE t1; + --echo connection con1 + connection con1; + reap; + disconnect con1; +--echo connection default +connection default; +DROP TABLE t1; + +# +# Example 2. +# +# Preparative cleanup. +--disable_warnings +SET DEBUG_SYNC= 'RESET'; +DROP TABLE IF EXISTS t1; +--enable_warnings +# +# Test. +CREATE TABLE t1 (c1 INT); +LOCK TABLE t1 WRITE; + --echo connection con1 + connect (con1,localhost,root,,); + # Retain action after use. First used by general_log. + SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked EXECUTE 2'; + send INSERT INTO t1 VALUES (1); +--echo connection default +connection default; +# Wait until INSERT waits for lock. +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +# let INSERT continue. +UNLOCK TABLES; + --echo connection con1 + connection con1; + --echo retrieve INSERT result. + reap; + disconnect con1; +--echo connection default +connection default; +DROP TABLE t1; + +# +# Cleanup after test case. +# Otherwise signal would contain 'flushed' here, +# which could confuse the next test. +# +SET DEBUG_SYNC= 'RESET'; + diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index 602e30687c8..d77f5eb128b 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -292,3 +292,47 @@ DROP TABLE t1; DROP FUNCTION f1; --echo End of 5.0 tests + +--echo # +--echo # Bug#46958: Assertion in Diagnostics_area::set_ok_status, trigger, +--echo # merge table +--echo # +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +CREATE TABLE t3 ( a INT ); + +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); +INSERT INTO t3 VALUES (1), (2); + +CREATE TRIGGER tr1 BEFORE DELETE ON t2 +FOR EACH ROW INSERT INTO no_such_table VALUES (1); + +--error ER_NO_SUCH_TABLE +DELETE t1, t2, t3 FROM t1, t2, t3; + +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +DROP TABLE t1, t2, t3; + +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +CREATE TABLE t3 ( a INT ); + +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); +INSERT INTO t3 VALUES (1), (2); + +CREATE TRIGGER tr1 AFTER DELETE ON t2 +FOR EACH ROW INSERT INTO no_such_table VALUES (1); + +--error ER_NO_SUCH_TABLE +DELETE t1, t2, t3 FROM t1, t2, t3; + +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +DROP TABLE t1, t2, t3; diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 5436b7166f4..ad7617b9403 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -10,7 +10,8 @@ # ############################################################################## kill : Bug#37780 2008-12-03 HHunger need some changes to be robust enough for pushbuild. -innodb_bug39438 : Bug#42383 2009-01-28 lsoares "This fails in embedded and on windows. Note that this test is not run on windows and on embedded in PB for main trees currently" query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically -init_connect : Bug#44920 2009-07-06 pcrews MTR not processing master.opt input properly on Windows. *Must be done this way due to the nature of the bug* - +partition_innodb_builtin : Bug#32430 2009-09-25 mattiasj Waiting for push of Innodb changes +partition_innodb_plugin : Bug#32430 2009-09-25 mattiasj Waiting for push of Innodb changes +innodb-autoinc : Bug#48482 2009-11-02 svoj innodb-autoinc.test fails with results difference +rpl_killed_ddl : Bug#45520: rpl_killed_ddl fails sporadically in pb2 diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index a77d1136840..bf4c23562cf 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -573,4 +573,44 @@ SELECT DISTINCT a, b, d, c FROM t1; DROP TABLE t1; +--echo # +--echo # Bug #46159: simple query that never returns +--echo # + +# Set max_heap_table_size to the minimum value so that GROUP BY table in the +# SELECT query below gets converted to MyISAM +SET @old_max_heap_table_size = @@max_heap_table_size; +SET @@max_heap_table_size = 16384; + +# Set sort_buffer_size to the mininum value so that remove_duplicates() calls +# remove_dup_with_compare() +SET @old_sort_buffer_size = @@sort_buffer_size; +SET @@sort_buffer_size = 32804; + +CREATE TABLE t1(c1 int, c2 VARCHAR(20)); +INSERT INTO t1 VALUES (1, '1'), (1, '1'), (2, '2'), (3, '1'), (3, '1'), (4, '4'); +# Now we just need to pad the table with random data so we have enough unique +# values to force conversion of the GROUP BY table to MyISAM +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; +INSERT INTO t1 SELECT 5 + 10000 * RAND(), '5' FROM t1; + +# First rows of the GROUP BY table that will be processed by +# remove_dup_with_compare() +SELECT c1, c2, COUNT(*) FROM t1 GROUP BY c1 LIMIT 4; + +# The actual test case +SELECT DISTINCT c2 FROM t1 GROUP BY c1 HAVING COUNT(*) > 1; + +# Cleanup + +DROP TABLE t1; +SET @@sort_buffer_size = @old_sort_buffer_size; +SET @@max_heap_table_size = @old_max_heap_table_size; + --echo End of 5.1 tests diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index 755e126baf2..77b49a8b1a5 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -135,6 +135,17 @@ EXPLAIN EXTENDED SELECT COUNT(a) FROM t1 USE KEY(a); DROP TABLE t1; +# +# Bug#45989 memory leak after explain encounters an error in the query +# +CREATE TABLE t1(a LONGTEXT); +INSERT INTO t1 VALUES (repeat('a',@@global.max_allowed_packet)); +INSERT INTO t1 VALUES (repeat('b',@@global.max_allowed_packet)); +--error ER_BAD_FIELD_ERROR +EXPLAIN SELECT DISTINCT 1 FROM t1, + (SELECT DISTINCTROW a AS away FROM t1 GROUP BY a WITH ROLLUP) as d1 + WHERE t1.a = d1.a; +DROP TABLE t1; # End of 5.0 tests. @@ -156,4 +167,24 @@ flush tables; SELECT OUTR.dt FROM t1 AS OUTR WHERE OUTR.dt IN ( SELECT INNR.dt FROM t2 AS INNR WHERE OUTR.t < '2005-11-13 7:41:31' ); drop tables t1, t2; +--echo # +--echo # Bug#48295: +--echo # explain extended crash with subquery and ONLY_FULL_GROUP_BY sql_mode +--echo # + +CREATE TABLE t1 (f1 INT); + +SELECT @@session.sql_mode INTO @old_sql_mode; +SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; + +# EXPLAIN EXTENDED (with subselect). used to crash. should give NOTICE. +--error ER_MIX_OF_GROUP_FUNC_AND_FIELDS +EXPLAIN EXTENDED SELECT 1 FROM t1 + WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t ); +SHOW WARNINGS; + +SET SESSION sql_mode=@old_sql_mode; + +DROP TABLE t1; + --echo End of 5.1 tests. diff --git a/mysql-test/t/flush_read_lock_kill.test b/mysql-test/t/flush_read_lock_kill.test index aeb09d52460..2d359383949 100644 --- a/mysql-test/t/flush_read_lock_kill.test +++ b/mysql-test/t/flush_read_lock_kill.test @@ -57,7 +57,7 @@ connection con1; # debug build running without our --debug=make_global..., will be # error 0 (no error). The only important thing to test is that on # debug builds with our --debug=make_global... we don't hang forever. ---error 0,1053,2013 +--error 0,1317,2013 reap; connection con2; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index b0a3d0feb79..6e39795a5d6 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -1006,3 +1006,51 @@ DROP TABLE t1; ### --echo End of 5.0 tests + +--echo # +--echo # BUG#47280 - strange results from count(*) with order by multiple +--echo # columns without where/group +--echo # + +--echo # +--echo # Initialize test +--echo # + +CREATE TABLE t1 ( + pk INT NOT NULL, + i INT, + PRIMARY KEY (pk) +); +INSERT INTO t1 VALUES (1,11),(2,12),(3,13); + +--echo # +--echo # Start test +--echo # All the following queries shall return 1 record +--echo # + +--echo +--echo # Masking all correct values {11...13} for column i in this result. +--replace_column 2 # +SELECT MAX(pk) as max, i +FROM t1 +ORDER BY max; + +--echo +EXPLAIN +SELECT MAX(pk) as max, i +FROM t1 +ORDER BY max; + +--echo +--echo # Only 11 is correct for collumn i in this result +SELECT MAX(pk) as max, i +FROM t1 +WHERE pk<2 +ORDER BY max; + +--echo # +--echo # Cleanup +--echo # +DROP TABLE t1; + +--echo End of 5.1 tests diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index adc074259ad..61ae812d874 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -456,4 +456,89 @@ SELECT SUM( DISTINCT e ) FROM t1 GROUP BY b,c,d HAVING (b,c,d) IN ((AVG( 1 ), 1 + c, 1 + d), (AVG( 1 ), 2 + c, 2 + d)); DROP TABLE t1; +--echo # +--echo # Bug #44139: Table scan when NULL appears in IN clause +--echo # + +--disable_warnings + +CREATE TABLE t1 ( + c_int INT NOT NULL, + c_decimal DECIMAL(5,2) NOT NULL, + c_float FLOAT(5, 2) NOT NULL, + c_bit BIT(10) NOT NULL, + c_date DATE NOT NULL, + c_datetime DATETIME NOT NULL, + c_timestamp TIMESTAMP NOT NULL, + c_time TIME NOT NULL, + c_year YEAR NOT NULL, + c_char CHAR(10) NOT NULL, + INDEX(c_int), INDEX(c_decimal), INDEX(c_float), INDEX(c_bit), INDEX(c_date), + INDEX(c_datetime), INDEX(c_timestamp), INDEX(c_time), INDEX(c_year), + INDEX(c_char)); + +INSERT INTO t1 (c_int) VALUES (1), (2), (3), (4), (5); +INSERT INTO t1 (c_int) SELECT 0 FROM t1; +INSERT INTO t1 (c_int) SELECT 0 FROM t1; + +--enable_warnings + +EXPLAIN SELECT * FROM t1 WHERE c_int IN (1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_int IN (NULL, 1, 2, 3); + +EXPLAIN SELECT * FROM t1 WHERE c_int IN (1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_int IN (1, NULL, 2, NULL, 3, NULL); +EXPLAIN SELECT * FROM t1 WHERE c_int IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_int IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (NULL, 1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_decimal IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_float IN (1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_float IN (NULL, 1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_float IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_float IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (NULL, 1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_bit IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_date + IN ('2009-09-01', '2009-09-02', '2009-09-03'); +EXPLAIN SELECT * FROM t1 WHERE c_date + IN (NULL, '2009-09-01', '2009-09-02', '2009-09-03'); +EXPLAIN SELECT * FROM t1 WHERE c_date IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_date IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_datetime + IN ('2009-09-01 00:00:01', '2009-09-02 00:00:01', '2009-09-03 00:00:01'); +EXPLAIN SELECT * FROM t1 WHERE c_datetime + IN (NULL, '2009-09-01 00:00:01', '2009-09-02 00:00:01', '2009-09-03 00:00:01'); +EXPLAIN SELECT * FROM t1 WHERE c_datetime IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_datetime IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_timestamp + IN ('2009-09-01 00:00:01', '2009-09-01 00:00:02', '2009-09-01 00:00:03'); +EXPLAIN SELECT * FROM t1 WHERE c_timestamp + IN (NULL, '2009-09-01 00:00:01', '2009-09-01 00:00:02', '2009-09-01 00:00:03'); +EXPLAIN SELECT * FROM t1 WHERE c_timestamp IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_timestamp IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_year IN (1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_year IN (NULL, 1, 2, 3); +EXPLAIN SELECT * FROM t1 WHERE c_year IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_year IN (NULL, NULL); + +EXPLAIN SELECT * FROM t1 WHERE c_char IN ('1', '2', '3'); +EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL, '1', '2', '3'); +EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL); +EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL, NULL); + +DROP TABLE t1; + +--echo # + --echo End of 5.1 tests diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 7cb7f7f72d2..66b9eabd385 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -1291,6 +1291,19 @@ INSERT INTO t1 VALUES ('aaaaaaaa'); SELECT LOAD_FILE(a) FROM t1; DROP TABLE t1; +# +# Bug#46815 CONCAT_WS returning wrong data +# +CREATE TABLE t1 (f2 VARCHAR(20)); +CREATE TABLE t2 (f2 VARCHAR(20)); + +INSERT INTO t1 VALUES ('MIN'),('MAX'); +INSERT INTO t2 VALUES ('LOAD'); + +SELECT CONCAT_WS('_', (SELECT t2.f2 FROM t2), t1.f2) AS concat_name FROM t1; + +DROP TABLE t1, t2; + --echo End of 5.0 tests diff --git a/mysql-test/t/gis-rtree.test b/mysql-test/t/gis-rtree.test index 944a00f008f..8ce4abf45d4 100644 --- a/mysql-test/t/gis-rtree.test +++ b/mysql-test/t/gis-rtree.test @@ -893,4 +893,25 @@ SELECT COUNT(*) FROM t1 IGNORE INDEX (b) WHERE DROP TABLE t1; + +--echo # +--echo # Bug #48258: Assertion failed when using a spatial index +--echo # +CREATE TABLE t1(a LINESTRING NOT NULL, SPATIAL KEY(a)); +INSERT INTO t1 VALUES + (GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')), + (GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')); +EXPLAIN SELECT 1 FROM t1 WHERE a = GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +SELECT 1 FROM t1 WHERE a = GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +EXPLAIN SELECT 1 FROM t1 WHERE a < GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +SELECT 1 FROM t1 WHERE a < GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +EXPLAIN SELECT 1 FROM t1 WHERE a <= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +SELECT 1 FROM t1 WHERE a <= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +EXPLAIN SELECT 1 FROM t1 WHERE a > GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +SELECT 1 FROM t1 WHERE a > GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +EXPLAIN SELECT 1 FROM t1 WHERE a >= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +SELECT 1 FROM t1 WHERE a >= GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)'); +DROP TABLE t1; + + --echo End of 5.0 tests. diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 4a60e777cc7..2d10c3bf1e1 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -655,6 +655,22 @@ insert into t1 values (),(),(); select min(`col002`) from t1 union select `col002` from t1; drop table t1; +--echo # +--echo # Bug #47780: crash when comparing GIS items from subquery +--echo # + +CREATE TABLE t1(a INT, b MULTIPOLYGON); +INSERT INTO t1 VALUES + (0, + GEOMFROMTEXT( + 'multipolygon(((1 2,3 4,5 6,7 8,9 8),(7 6,5 4,3 2,1 2,3 4)))')); + +--echo # must not crash +SELECT 1 FROM t1 WHERE a <> (SELECT GEOMETRYCOLLECTIONFROMWKB(b) FROM t1); + +DROP TABLE t1; + + --echo End of 5.0 tests diff --git a/mysql-test/t/grant3.test b/mysql-test/t/grant3.test index 9a635048774..437fc9a278f 100644 --- a/mysql-test/t/grant3.test +++ b/mysql-test/t/grant3.test @@ -163,6 +163,41 @@ connection default; DROP USER 'mysqltest1'@'%'; DROP DATABASE mysqltest_1; +--echo # +--echo # Bug#41597 - After rename of user, there are additional grants +--echo # when grants are reapplied. +--echo # + +CREATE DATABASE temp; +CREATE TABLE temp.t1(a INT, b VARCHAR(10)); +INSERT INTO temp.t1 VALUES(1, 'name1'); +INSERT INTO temp.t1 VALUES(2, 'name2'); +INSERT INTO temp.t1 VALUES(3, 'name3'); + + +CREATE USER 'user1'@'%'; +RENAME USER 'user1'@'%' TO 'user2'@'%'; +--echo # Show privileges after rename and BEFORE grant +SHOW GRANTS FOR 'user2'@'%'; +GRANT SELECT (a), INSERT (b) ON `temp`.`t1` TO 'user2'@'%'; +--echo # Show privileges after rename and grant +SHOW GRANTS FOR 'user2'@'%'; + +--echo # Connect as the renamed user +connect (conn1, localhost, user2,,); +connection conn1; +SHOW GRANTS; +SELECT a FROM temp.t1; +--echo # Check for additional privileges by accessing a +--echo # non privileged column. We shouldn't be able to +--echo # access this column. +--error ER_COLUMNACCESS_DENIED_ERROR +SELECT b FROM temp.t1; +disconnect conn1; + +connection default; +DROP USER 'user2'@'%'; +DROP DATABASE temp; --echo End of 5.0 tests diff --git a/mysql-test/t/grant_lowercase_fs.test b/mysql-test/t/grant_lowercase_fs.test new file mode 100644 index 00000000000..f57f950ec8c --- /dev/null +++ b/mysql-test/t/grant_lowercase_fs.test @@ -0,0 +1,30 @@ +-- source include/have_case_insensitive_fs.inc +-- source include/not_embedded.inc + + +# +# Bug#41049 does syntax "grant" case insensitive? +# +create database db1; +GRANT CREATE ON db1.* to user_1@localhost; +GRANT SELECT ON db1.* to USER_1@localhost; + +connect (con1,localhost,user_1,,db1); +CREATE TABLE t1(f1 int); +--error 1142 +SELECT * FROM t1; +connect (con2,localhost,USER_1,,db1); +SELECT * FROM t1; +--error 1142 +CREATE TABLE t2(f1 int); + +connection default; +disconnect con1; +disconnect con2; + +REVOKE ALL PRIVILEGES, GRANT OPTION FROM user_1@localhost; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM USER_1@localhost; +DROP USER user_1@localhost; +DROP USER USER_1@localhost; +DROP DATABASE db1; +use test; diff --git a/mysql-test/t/information_schema_db.test b/mysql-test/t/information_schema_db.test index 59cd0fba024..bfe6745f5ae 100644 --- a/mysql-test/t/information_schema_db.test +++ b/mysql-test/t/information_schema_db.test @@ -181,7 +181,6 @@ show fields from testdb_1.v7; --error ER_TABLEACCESS_DENIED_ERROR show create view testdb_1.v7; ---error ER_VIEW_NO_EXPLAIN show create view v4; #--error ER_VIEW_NO_EXPLAIN show fields from v4; diff --git a/mysql-test/t/innodb-autoinc.test b/mysql-test/t/innodb-autoinc.test index 87ad470949d..3f45bb9d003 100644 --- a/mysql-test/t/innodb-autoinc.test +++ b/mysql-test/t/innodb-autoinc.test @@ -156,7 +156,7 @@ DROP TABLE t1; # # Test changes to AUTOINC next value calculation SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES (NULL),(5),(NULL); @@ -173,7 +173,7 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(0); @@ -193,13 +193,13 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(-1); SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; INSERT INTO t1 VALUES (-2), (NULL),(2),(NULL); INSERT INTO t1 VALUES (250),(NULL); SELECT * FROM t1; @@ -214,13 +214,13 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(-1); SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; INSERT INTO t1 VALUES (-2); INSERT INTO t1 VALUES (NULL); INSERT INTO t1 VALUES (2); @@ -240,13 +240,13 @@ DROP TABLE t1; # Reset the AUTOINC session variables SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(-1); SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; INSERT INTO t1 VALUES (-2),(NULL),(2),(NULL); INSERT INTO t1 VALUES (250),(NULL); SELECT * FROM t1; @@ -262,7 +262,7 @@ DROP TABLE t1; # Check for overflow handling when increment is > 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -271,7 +271,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (9223372036854775794); #-- 2^63 - 14 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; # This should just fit INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); SELECT * FROM t1; @@ -281,7 +281,7 @@ DROP TABLE t1; # Check for overflow handling when increment and offser are > 1 SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -290,7 +290,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (18446744073709551603); #-- 2^64 - 13 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; # This should fail because of overflow but it doesn't, it seems to be # a MySQL server bug. It wraps around to 0 for the last value. # See MySQL Bug# 39828 @@ -313,7 +313,7 @@ DROP TABLE t1; # Check for overflow handling when increment and offset are odd numbers SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -322,7 +322,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (18446744073709551603); #-- 2^64 - 13 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; # This should fail because of overflow but it doesn't. It fails with # a duplicate entry message because of a MySQL server bug, it wraps # around. See MySQL Bug# 39828, once MySQL fix the bug we can replace @@ -344,7 +344,7 @@ DROP TABLE t1; # and check for large -ve numbers SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -355,7 +355,7 @@ INSERT INTO t1 VALUES(-9223372036854775807); #-- -2^63 + 1 INSERT INTO t1 VALUES(-9223372036854775808); #-- -2^63 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; INSERT INTO t1 VALUES (NULL),(NULL), (NULL); SELECT * FROM t1; DROP TABLE t1; @@ -364,7 +364,7 @@ DROP TABLE t1; # large numbers 2^60 SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; DROP TABLE IF EXISTS t1; CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; # TODO: Fix the autoinc init code @@ -373,7 +373,7 @@ INSERT INTO t1 VALUES(NULL); INSERT INTO t1 VALUES (18446744073709551610); #-- 2^64 - 2 SELECT * FROM t1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; # This should fail because of overflow but it doesn't. It wraps around # and the autoinc values look bogus too. # See MySQL Bug# 39828, once MySQL fix the bug we can enable the error @@ -396,7 +396,7 @@ DROP TABLE t1; # SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "auto_inc%"; +SHOW VARIABLES LIKE "%auto_inc%"; CREATE TABLE t1 (c1 DOUBLE NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB; INSERT INTO t1 VALUES(NULL, 1); INSERT INTO t1 VALUES(NULL, 2); @@ -478,3 +478,145 @@ INSERT INTO t2 SELECT c1 FROM t1; INSERT INTO t2 SELECT NULL FROM t1; DROP TABLE t1; DROP TABLE t2; +# +# 44030: Error: (1500) Couldn't read the MAX(ID) autoinc value from +# the index (PRIMARY) +# This test requires a restart of the server +SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; +CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (null); +INSERT INTO t1 VALUES (null); +ALTER TABLE t1 CHANGE c1 d1 INT NOT NULL AUTO_INCREMENT; +SELECT * FROM t1; +# Restart the server +-- source include/restart_mysqld.inc +# The MySQL and InnoDB data dictionaries should now be out of sync. +# The select should print message to the error log +SELECT * FROM t1; +# MySQL have made a change (http://lists.mysql.com/commits/75268) that no +# longer results in the two data dictionaries being out of sync. If they +# revert their changes then this check for ER_AUTOINC_READ_FAILED will need +# to be enabled. +-- error ER_AUTOINC_READ_FAILED,1467 +INSERT INTO t1 VALUES(null); +ALTER TABLE t1 AUTO_INCREMENT = 3; +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES(null); +SELECT * FROM t1; +DROP TABLE t1; + +# If the user has specified negative values for an AUTOINC column then +# InnoDB should ignore those values when setting the table's max value. +SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; +SHOW VARIABLES LIKE "%auto_inc%"; +# TINYINT +CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-127, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (c1 TINYINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-127, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; +# +# SMALLINT +# +CREATE TABLE t1 (c1 SMALLINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-32767, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (c1 SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-32757, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; +# +# MEDIUMINT +# +CREATE TABLE t1 (c1 MEDIUMINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-8388607, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (c1 MEDIUMINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-8388607, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; +# +# INT +# +CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-2147483647, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (c1 INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-2147483647, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; +# +# BIGINT +# +CREATE TABLE t1 (c1 BIGINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-9223372036854775807, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (c1 BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (-1, 'innodb'); +INSERT INTO t1 VALUES (-9223372036854775807, 'innodb'); +INSERT INTO t1 VALUES (NULL, NULL); +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; +# +# End negative number check + +## +# 47125: auto_increment start value is ignored if an index is created +# and engine=innodb +# +CREATE TABLE T1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) AUTO_INCREMENT=10 ENGINE=InnoDB; +CREATE INDEX i1 on T1(c2); +SHOW CREATE TABLE T1; +INSERT INTO T1 (c2) values (0); +SELECT * FROM T1; +DROP TABLE T1; diff --git a/mysql-test/t/innodb_bug39438.test b/mysql-test/t/innodb_bug39438.test index 4dc3d957c39..2a51e5fcbb8 100644 --- a/mysql-test/t/innodb_bug39438.test +++ b/mysql-test/t/innodb_bug39438.test @@ -9,6 +9,10 @@ -- source include/have_innodb.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Error: table 'test/bug39438'"); +--enable_query_log + SET storage_engine=InnoDB; # we care only that the following SQL commands do not crash the server diff --git a/mysql-test/t/innodb_bug44369.test b/mysql-test/t/innodb_bug44369.test new file mode 100644 index 00000000000..238dc3d8fb1 --- /dev/null +++ b/mysql-test/t/innodb_bug44369.test @@ -0,0 +1,21 @@ +# This is the test for bug 44369. We should +# block table creation with columns match +# some innodb internal reserved key words, +# both case sensitively and insensitely. + +--source include/have_innodb.inc + +# This create table operation should fail. +--error ER_CANT_CREATE_TABLE +create table bug44369 (DB_ROW_ID int) engine=innodb; + +# This create should fail as well +--error ER_CANT_CREATE_TABLE +create table bug44369 (db_row_id int) engine=innodb; + +show warnings; + +--error ER_CANT_CREATE_TABLE +create table bug44369 (db_TRX_Id int) engine=innodb; + +show warnings; diff --git a/mysql-test/t/innodb_bug46000.test b/mysql-test/t/innodb_bug46000.test new file mode 100644 index 00000000000..03942c86c98 --- /dev/null +++ b/mysql-test/t/innodb_bug46000.test @@ -0,0 +1,34 @@ +# This is the test for bug 46000. We shall +# block any index creation with the name of +# "GEN_CLUST_INDEX", which is the reserved +# name for innodb default primary index. + +--source include/have_innodb.inc + +# This 'create table' operation should fail because of +# using the reserve name as its index name. +--error ER_WRONG_NAME_FOR_INDEX +create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; + +# Mixed upper/lower case of the reserved key words +--error ER_WRONG_NAME_FOR_INDEX +create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; + +show warnings; + +create table bug46000(id int) engine=innodb; + +# This 'create index' operation should fail. +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_WRONG_NAME_FOR_INDEX +create index GEN_CLUST_INDEX on bug46000(id); + +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show warnings; + +# This 'create index' operation should succeed, no +# temp table left from last failed create index +# operation. +create index idx on bug46000(id); + +drop table bug46000; diff --git a/mysql-test/t/innodb_bug47777.test b/mysql-test/t/innodb_bug47777.test new file mode 100644 index 00000000000..8f2985b2cf0 --- /dev/null +++ b/mysql-test/t/innodb_bug47777.test @@ -0,0 +1,24 @@ +# This is the test for bug 47777. GEOMETRY +# data is treated as BLOB data in innodb. +# Consequently, its key value generation/storing +# should follow the process for the BLOB +# datatype as well. + +--source include/have_innodb.inc + +create table bug47777(c2 linestring not null, primary key (c2(1))) engine=innodb; + +insert into bug47777 values (geomfromtext('linestring(1 2,3 4,5 6,7 8,9 10)')); + +# Verify correct row get inserted. +select count(*) from bug47777 where c2 =geomfromtext('linestring(1 2,3 4,5 6,7 8,9 10)'); + +# Update table bug47777 should be successful. +update bug47777 set c2=GeomFromText('POINT(1 1)'); + +# Verify the row get updated successfully. The original +# c2 value should be changed to GeomFromText('POINT(1 1)'). +select count(*) from bug47777 where c2 =geomfromtext('linestring(1 2,3 4,5 6,7 8,9 10)'); +select count(*) from bug47777 where c2 = GeomFromText('POINT(1 1)'); + +drop table bug47777; diff --git a/mysql-test/t/bug40113-master.opt b/mysql-test/t/innodb_lock_wait_timeout_1-master.opt index 462f8fbe828..462f8fbe828 100644 --- a/mysql-test/t/bug40113-master.opt +++ b/mysql-test/t/innodb_lock_wait_timeout_1-master.opt diff --git a/mysql-test/t/innodb_lock_wait_timeout_1.test b/mysql-test/t/innodb_lock_wait_timeout_1.test new file mode 100644 index 00000000000..e42e9f3e37c --- /dev/null +++ b/mysql-test/t/innodb_lock_wait_timeout_1.test @@ -0,0 +1,230 @@ +--source include/have_innodb.inc + +--echo # +--echo # Bug #40113: Embedded SELECT inside UPDATE or DELETE can timeout +--echo # without error +--echo # + +CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b)) ENGINE=InnoDB; + +INSERT INTO t1 (a,b) VALUES (1070109,99); + +CREATE TABLE t2 (b int, a int, PRIMARY KEY (b)) ENGINE=InnoDB; + +INSERT INTO t2 (b,a) VALUES (7,1070109); + +SELECT * FROM t1; + +BEGIN; + +SELECT b FROM t2 WHERE b=7 FOR UPDATE; + +CONNECT (addconroot, localhost, root,,); +CONNECTION addconroot; + +BEGIN; + +--error ER_LOCK_WAIT_TIMEOUT +SELECT b FROM t2 WHERE b=7 FOR UPDATE; + +--error ER_LOCK_WAIT_TIMEOUT +INSERT INTO t1 (a) VALUES ((SELECT a FROM t2 WHERE b=7)); + +--error ER_LOCK_WAIT_TIMEOUT +UPDATE t1 SET a='7000000' WHERE a=(SELECT a FROM t2 WHERE b=7); + +--error ER_LOCK_WAIT_TIMEOUT +DELETE FROM t1 WHERE a=(SELECT a FROM t2 WHERE b=7); + +SELECT * FROM t1; + +CONNECTION default; +DISCONNECT addconroot; + +DROP TABLE t2, t1; + +--echo # End of 5.0 tests + +--echo # +--echo # Bug#46539 Various crashes on INSERT IGNORE SELECT + SELECT +--echo # FOR UPDATE +--echo # +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (a int primary key auto_increment, + b int, index(b)) engine=innodb; +insert into t1 (b) values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10); +set autocommit=0; +begin; +select * from t1 where b=5 for update; +connect (con1, localhost, root,,); +connection con1; +--error ER_LOCK_WAIT_TIMEOUT +insert ignore into t1 (b) select a as b from t1; +connection default; +--echo # Cleanup +--echo # +disconnect con1; +commit; +set autocommit=default; +drop table t1; + +--echo # +--echo # Bug#41756 Strange error messages about locks from InnoDB +--echo # +--disable_warnings +drop table if exists t1; +--enable_warnings +--echo # In the default transaction isolation mode, and/or with +--echo # innodb_locks_unsafe_for_binlog=OFF, handler::unlock_row() +--echo # in InnoDB does nothing. +--echo # Thus in order to reproduce the condition that led to the +--echo # warning, one needs to relax isolation by either +--echo # setting a weaker tx_isolation value, or by turning on +--echo # the unsafe replication switch. +--echo # For testing purposes, choose to tweak the isolation level, +--echo # since it's settable at runtime, unlike +--echo # innodb_locks_unsafe_for_binlog, which is +--echo # only a command-line switch. +--echo # +set @@session.tx_isolation="read-committed"; + +--echo # Prepare data. We need a table with a unique index, +--echo # for join_read_key to be used. The other column +--echo # allows to control what passes WHERE clause filter. +create table t1 (a int primary key, b int) engine=innodb; +--echo # Let's make sure t1 has sufficient amount of rows +--echo # to exclude JT_ALL access method when reading it, +--echo # i.e. make sure that JT_EQ_REF(a) is always preferred. +insert into t1 values (1,1), (2,null), (3,1), (4,1), + (5,1), (6,1), (7,1), (8,1), (9,1), (10,1), + (11,1), (12,1), (13,1), (14,1), (15,1), + (16,1), (17,1), (18,1), (19,1), (20,1); +--echo # +--echo # Demonstrate that for the SELECT statement +--echo # used later in the test JT_EQ_REF access method is used. +--echo # +--vertical_results +explain +select 1 from t1 natural join (select 2 as a, 1 as b union all + select 2 as a, 2 as b) as t2 for update; +--horizontal_results +--echo # +--echo # Demonstrate that the reported SELECT statement +--echo # no longer produces warnings. +--echo # +select 1 from t1 natural join (select 2 as a, 1 as b union all + select 2 as a, 2 as b) as t2 for update; +commit; +--echo # +--echo # Demonstrate that due to lack of inter-sweep "reset" function, +--echo # we keep some non-matching records locked, even though we know +--echo # we could unlock them. +--echo # To do that, show that if there is only one distinct value +--echo # for a in t2 (a=2), we will keep record (2,null) in t1 locked. +--echo # But if we add another value for "a" to t2, say 6, +--echo # join_read_key cache will be pruned at least once, +--echo # and thus record (2, null) in t1 will get unlocked. +--echo # +begin; +select 1 from t1 natural join (select 2 as a, 1 as b union all + select 2 as a, 2 as b) as t2 for update; +connect (con1,localhost,root,,); +--echo # +--echo # Switching to connection con1 +connection con1; +--echo # We should be able to delete all records from t1 except (2, null), +--echo # since they were not locked. +begin; +--echo # Delete in series of 3 records so that full scan +--echo # is not used and we're not blocked on record (2,null) +delete from t1 where a in (1,3,4); +delete from t1 where a in (5,6,7); +delete from t1 where a in (8,9,10); +delete from t1 where a in (11,12,13); +delete from t1 where a in (14,15,16); +delete from t1 where a in (17,18); +delete from t1 where a in (19,20); +--echo # +--echo # Record (2, null) is locked. This is actually unnecessary, +--echo # because the previous select returned no rows. +--echo # Just demonstrate the effect. +--echo # +--error ER_LOCK_WAIT_TIMEOUT +delete from t1; +rollback; +--echo # +--echo # Switching to connection default +connection default; +--echo # +--echo # Show that the original contents of t1 is intact: +select * from t1; +commit; +--echo # +--echo # Have a one more record in t2 to show that +--echo # if join_read_key cache is purned, the current +--echo # row under the cursor is unlocked (provided, this row didn't +--echo # match the partial WHERE clause, of course). +--echo # Sic: the result of this test dependent on the order of retrieval +--echo # of records --echo # from the derived table, if ! +--echo # We use DELETE to disable the JOIN CACHE. This DELETE modifies no +--echo # records. It also should leave no InnoDB row locks. +--echo # +begin; +delete t1.* from t1 natural join (select 2 as a, 2 as b union all + select 0 as a, 0 as b) as t2; +--echo # Demonstrate that nothing was deleted form t1 +select * from t1; +--echo # +--echo # Switching to connection con1 +connection con1; +begin; +--echo # Since there is another distinct record in the derived table +--echo # the previous matching record in t1 -- (2,null) -- was unlocked. +delete from t1; +--echo # We will need the contents of the table again. +rollback; +select * from t1; +commit; +--echo # +--echo # Switching to connection default +connection default; +rollback; +begin; +--echo # +--echo # Before this patch, we could wrongly unlock a record +--echo # that was cached and later used in a join. Demonstrate that +--echo # this is no longer the case. +--echo # Sic: this test is also order-dependent (i.e. the +--echo # the bug would show up only if the first record in the union +--echo # is retreived and processed first. +--echo # +--echo # Verify that JT_EQ_REF is used. +--vertical_results +explain +select 1 from t1 natural join (select 3 as a, 2 as b union all + select 3 as a, 1 as b) as t2 for update; +--horizontal_results +--echo # Lock the record. +select 1 from t1 natural join (select 3 as a, 2 as b union all + select 3 as a, 1 as b) as t2 for update; +--echo # Switching to connection con1 +connection con1; +--echo # +--echo # We should not be able to delete record (3,1) from t1, +--echo # (previously it was possible). +--echo # +--error ER_LOCK_WAIT_TIMEOUT +delete from t1 where a=3; +--echo # Switching to connection default +connection default; +commit; + +disconnect con1; +set @@session.tx_isolation=default; +drop table t1; + +--echo # +--echo # End of 5.1 tests +--echo # diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index d604bcfe769..8d2b70d4a0f 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -463,4 +463,33 @@ EXPLAIN SELECT * FROM t1 FORCE INDEX(PRIMARY) WHERE b=1 AND c=1 ORDER BY a; DROP TABLE t1; +--echo # +--echo # Bug #47963: Wrong results when index is used +--echo # +CREATE TABLE t1( + a VARCHAR(5) NOT NULL, + b VARCHAR(5) NOT NULL, + c DATETIME NOT NULL, + KEY (c) +) ENGINE=InnoDB; +INSERT INTO t1 VALUES('TEST', 'TEST', '2009-10-09 00:00:00'); +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00' AND c <= '2009-10-09 00:00:00'; +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00.0' AND c <= '2009-10-09 00:00:00.0'; +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00.0' AND c <= '2009-10-09 00:00:00'; +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00' AND c <= '2009-10-09 00:00:00.0'; +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00.000' AND c <= '2009-10-09 00:00:00.000'; +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00.00' AND c <= '2009-10-09 00:00:00.001'; +SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00'; +EXPLAIN SELECT * FROM t1 WHERE a = 'TEST' AND + c >= '2009-10-09 00:00:00.001' AND c <= '2009-10-09 00:00:00.00'; +DROP TABLE t1; + + --echo End of 5.1 tests diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index 50c40e38b5b..d740445fb4d 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -392,4 +392,32 @@ insert into t1 values(1),(2),(3); create table t2 (key(f1)) engine=myisam select sql_buffer_result f1 from t1; check table t2 extended; drop table t1,t2; + --echo End of 5.0 tests + +# The following is not relevant for MariaDB as we are using Maria for +# tmp tables. + +--echo ################################################################## +--echo # +--echo # Bug #46075: Assertion failed: 0, file .\protocol.cc, line 416 +--echo # + +CREATE TABLE t1(a INT); +# To force MyISAM temp. table in the following INSERT ... SELECT. +SET max_heap_table_size = 16384; +# To overflow the temp. table. +SET @old_myisam_data_pointer_size = @@myisam_data_pointer_size; +SET GLOBAL myisam_data_pointer_size = 2; + +INSERT INTO t1 VALUES (1), (2), (3), (4), (5); + +call mtr.add_suppression("mysqld: The table '.*#sql.*' is full"); +--error 0,ER_RECORD_FILE_FULL,ER_RECORD_FILE_FULL +INSERT IGNORE INTO t1 SELECT t1.a FROM t1,t1 t2,t1 t3,t1 t4,t1 t5,t1 t6,t1 t7; + +# Cleanup +SET GLOBAL myisam_data_pointer_size = @old_myisam_data_pointer_size; +DROP TABLE t1; + +--echo End of 5.1 tests diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test index b5e30e63f54..dbf36dedec8 100644 --- a/mysql-test/t/join.test +++ b/mysql-test/t/join.test @@ -729,4 +729,78 @@ SELECT * FROM t1 JOIN t2 ON b=c ORDER BY a; SELECT * FROM t1 JOIN t2 ON a=c ORDER BY a; DROP TABLE IF EXISTS t1,t2; + + +--echo # +--echo # Bug #42116: Mysql crash on specific query +--echo # +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +CREATE TABLE t3 (a INT, INDEX (a)); +CREATE TABLE t4 (a INT); +CREATE TABLE t5 (a INT); +CREATE TABLE t6 (a INT); + +INSERT INTO t1 VALUES (1), (1), (1); + +INSERT INTO t2 VALUES +(2), (2), (2), (2), (2), (2), (2), (2), (2), (2); + +INSERT INTO t3 VALUES +(3), (3), (3), (3), (3), (3), (3), (3), (3), (3); + +EXPLAIN +SELECT * +FROM + t1 JOIN t2 ON t1.a = t2.a + LEFT JOIN + ( + ( + t3 LEFT JOIN t4 ON t3.a = t4.a + ) + LEFT JOIN + ( + t5 LEFT JOIN t6 ON t5.a = t6.a + ) + ON t4.a = t5.a + ) + ON t1.a = t3.a; + +SELECT * +FROM + t1 JOIN t2 ON t1.a = t2.a + LEFT JOIN + ( + ( + t3 LEFT JOIN t4 ON t3.a = t4.a + ) + LEFT JOIN + ( + t5 LEFT JOIN t6 ON t5.a = t6.a + ) + ON t4.a = t5.a + ) + ON t1.a = t3.a; + +DROP TABLE t1,t2,t3,t4,t5,t6; + --echo End of 5.0 tests. + + +# +# Bug#47150 Assertion in Field_long::val_int() on MERGE + TRIGGER + multi-table UPDATE +# +CREATE TABLE t1 (f1 int); + +CREATE TABLE t2 (f1 int); +INSERT INTO t2 VALUES (1); +CREATE VIEW v1 AS SELECT * FROM t2; + +PREPARE stmt FROM 'UPDATE t2 AS A NATURAL JOIN v1 B SET B.f1 = 1'; +EXECUTE stmt; +EXECUTE stmt; + +DEALLOCATE PREPARE stmt; + +DROP VIEW v1; +DROP TABLE t1, t2; diff --git a/mysql-test/t/kill.test b/mysql-test/t/kill.test index 44d04abf486..b199a1224c3 100644 --- a/mysql-test/t/kill.test +++ b/mysql-test/t/kill.test @@ -99,7 +99,7 @@ select ((@id := kill_id) - kill_id) from t3; kill @id; connection conn1; --- error 1053,2013 +-- error 1317,2013 reap; connection default; diff --git a/mysql-test/t/locale.test b/mysql-test/t/locale.test new file mode 100644 index 00000000000..7ceb49fd1f4 --- /dev/null +++ b/mysql-test/t/locale.test @@ -0,0 +1,18 @@ +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +--echo Start of 5.4 tests +--echo # +--echo # Bug#43207 wrong LC_TIME names for romanian locale +--echo # +SET NAMES utf8; +SET lc_time_names=ro_RO; +SELECT DATE_FORMAT('2001-01-01', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-02', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-03', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-04', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-05', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-06', '%w %a %W'); +SELECT DATE_FORMAT('2001-01-07', '%w %a %W'); +--echo End of 5.4 tests diff --git a/mysql-test/t/lowercase_fs_off.test b/mysql-test/t/lowercase_fs_off.test index 878564c32ab..86d1e084c29 100644 --- a/mysql-test/t/lowercase_fs_off.test +++ b/mysql-test/t/lowercase_fs_off.test @@ -29,3 +29,65 @@ disconnect master; connection default; # End of 4.1 tests + +# +# Bug#41049 does syntax "grant" case insensitive? +# +CREATE DATABASE d1; +USE d1; +CREATE TABLE T1(f1 INT); +CREATE TABLE t1(f1 INT); +GRANT SELECT ON T1 to user_1@localhost; + +connect (con1,localhost,user_1,,d1); +--error ER_TABLEACCESS_DENIED_ERROR +select * from t1; +select * from T1; +connection default; +GRANT SELECT ON t1 to user_1@localhost; +connection con1; +select * from information_schema.table_privileges; +connection default; +disconnect con1; + +REVOKE ALL PRIVILEGES, GRANT OPTION FROM user_1@localhost; +DROP USER user_1@localhost; +DROP DATABASE d1; +USE test; + +CREATE DATABASE db1; +USE db1; +CREATE PROCEDURE p1() BEGIN END; +CREATE FUNCTION f1(i INT) RETURNS INT RETURN i+1; + +GRANT USAGE ON db1.* to user_1@localhost; +GRANT EXECUTE ON PROCEDURE db1.P1 to user_1@localhost; +GRANT EXECUTE ON FUNCTION db1.f1 to user_1@localhost; +GRANT UPDATE ON db1.* to USER_1@localhost; + +connect (con1,localhost,user_1,,db1); +call p1(); +call P1(); +select f1(1); +connect (con2,localhost,USER_1,,db1); +--error ER_PROCACCESS_DENIED_ERROR +call p1(); +--error ER_PROCACCESS_DENIED_ERROR +call P1(); +--error ER_PROCACCESS_DENIED_ERROR +select f1(1); + +connection default; +disconnect con1; +disconnect con2; + +REVOKE ALL PRIVILEGES, GRANT OPTION FROM user_1@localhost; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM USER_1@localhost; +DROP FUNCTION f1; +DROP PROCEDURE p1; +DROP USER user_1@localhost; +DROP USER USER_1@localhost; +DROP DATABASE db1; +use test; + +# End of 5.0 tests diff --git a/mysql-test/t/lowercase_mixed_tmpdir_innodb-master.opt b/mysql-test/t/lowercase_mixed_tmpdir_innodb-master.opt new file mode 100644 index 00000000000..272f91d629c --- /dev/null +++ b/mysql-test/t/lowercase_mixed_tmpdir_innodb-master.opt @@ -0,0 +1,2 @@ +--lower-case-table-names=2 +--tmpdir=$MYSQLTEST_VARDIR/tmp/MixedCase diff --git a/mysql-test/t/lowercase_mixed_tmpdir_innodb-master.sh b/mysql-test/t/lowercase_mixed_tmpdir_innodb-master.sh new file mode 100644 index 00000000000..95c26e3aa02 --- /dev/null +++ b/mysql-test/t/lowercase_mixed_tmpdir_innodb-master.sh @@ -0,0 +1,6 @@ +# This test requires a non-lowercase tmpdir directory on a case-sensitive +# filesystem. + +d="$MYSQLTEST_VARDIR/tmp/MixedCase" +test -d "$d" || mkdir "$d" +rm -f "$d"/* diff --git a/mysql-test/t/lowercase_mixed_tmpdir_innodb.test b/mysql-test/t/lowercase_mixed_tmpdir_innodb.test new file mode 100644 index 00000000000..e3b9b7b2a32 --- /dev/null +++ b/mysql-test/t/lowercase_mixed_tmpdir_innodb.test @@ -0,0 +1,12 @@ +--source include/have_lowercase2.inc +--source include/have_innodb.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (id int) engine=InnoDB; +insert into t1 values (1); +create temporary table t2 engine=InnoDB select * from t1; +drop temporary table t2; +drop table t1; diff --git a/mysql-test/t/lowercase_table3.test b/mysql-test/t/lowercase_table3.test index 4748953fe95..f7ca8211288 100644 --- a/mysql-test/t/lowercase_table3.test +++ b/mysql-test/t/lowercase_table3.test @@ -9,7 +9,7 @@ --source include/have_case_insensitive_file_system.inc --source include/not_windows.inc -call mtr.add_suppression("Cannot find or open table test/BUG29839 from .*"); +call mtr.add_suppression("Cannot find or open table test/BUG29839 from"); --disable_warnings DROP TABLE IF EXISTS t1,T1; diff --git a/mysql-test/t/myisam-system.test b/mysql-test/t/myisam-system.test index dc5bb58b6a2..d908e639a4e 100644 --- a/mysql-test/t/myisam-system.test +++ b/mysql-test/t/myisam-system.test @@ -12,11 +12,11 @@ let $MYSQLD_DATADIR= `select @@datadir`; drop table if exists t1; create table t1 (a int) engine=myisam; --remove_file $MYSQLD_DATADIR/test/t1.MYI ---error 1051,6 +--error ER_BAD_TABLE_ERROR,6 drop table t1; create table t1 (a int) engine=myisam; --remove_file $MYSQLD_DATADIR/test/t1.MYD ---error 1105,6,29 +--error ER_BAD_TABLE_ERROR,6,29 drop table t1; ---error 1051 +--error ER_BAD_TABLE_ERROR drop table t1; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 69a0330fd9d..41445cea8ce 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -1549,4 +1549,50 @@ SELECT h+0, d + 0, e, g + 0 FROM t1; DROP TABLE t1; +--echo # +--echo # Test of BUG#35570 CHECKSUM TABLE unreliable if LINESTRING field +--echo # (same content / differen checksum) +--echo # + +CREATE TABLE t1 (line LINESTRING NOT NULL) engine=myisam; +INSERT INTO t1 VALUES (GeomFromText("POINT(0 0)")); +checksum table t1; +CREATE TABLE t2 (line LINESTRING NOT NULL) engine=myisam; +INSERT INTO t2 VALUES (GeomFromText("POINT(0 0)")); +checksum table t2; +CREATE TABLE t3 select * from t1; +checksum table t3; +drop table t1,t2,t3; + + +# +# BUG#47073 - valgrind errs, corruption,failed repair of partition, +# low myisam_sort_buffer_size +# +CREATE TABLE t1(a INT, b CHAR(10), KEY(a), KEY(b)); +INSERT INTO t1 VALUES(1,'0'),(2,'0'),(3,'0'),(4,'0'),(5,'0'), + (6,'0'),(7,'0'); +INSERT INTO t1 SELECT a+10,b FROM t1; +INSERT INTO t1 SELECT a+20,b FROM t1; +INSERT INTO t1 SELECT a+40,b FROM t1; +INSERT INTO t1 SELECT a+80,b FROM t1; +INSERT INTO t1 SELECT a+160,b FROM t1; +INSERT INTO t1 SELECT a+320,b FROM t1; +INSERT INTO t1 SELECT a+640,b FROM t1; +INSERT INTO t1 SELECT a+1280,b FROM t1; +INSERT INTO t1 SELECT a+2560,b FROM t1; +INSERT INTO t1 SELECT a+5120,b FROM t1; +SET myisam_sort_buffer_size=4; +REPAIR TABLE t1; + +SET myisam_repair_threads=2; +# May report different values depending on threads activity. +--disable_result_log +REPAIR TABLE t1; +--enable_result_log +SET myisam_repair_threads=@@global.myisam_repair_threads; +SET myisam_sort_buffer_size=@@global.myisam_sort_buffer_size; +CHECK TABLE t1; +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/mysql-test/t/myisam_crash_before_flush_keys.test b/mysql-test/t/myisam_crash_before_flush_keys.test index d6559f7760d..1860ddd27e3 100644 --- a/mysql-test/t/myisam_crash_before_flush_keys.test +++ b/mysql-test/t/myisam_crash_before_flush_keys.test @@ -26,12 +26,6 @@ SET SESSION debug="d,crash_before_flush_keys"; --error 2013 FLUSH TABLE t1; ---echo # Run MYISAMCHK tool to check the table t1 and repair ---replace_result $MYISAMCHK MYISAMCHK $MYSQLD_DATADIR MYSQLD_DATADIR ---error 255 ---exec $MYISAMCHK -cs $MYSQLD_DATADIR/test/t1 2>&1 ---exec $MYISAMCHK -rs $MYSQLD_DATADIR/test/t1 - --echo # Write file to make mysql-test-run.pl start the server --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect @@ -42,8 +36,6 @@ FLUSH TABLE t1; --echo # it to be back online again --source include/wait_until_connected_again.inc -SHOW CREATE TABLE t1; - -SELECT * FROM t1 FORCE INDEX (PRIMARY); - +# Must report that the table wasn't closed properly +CHECK TABLE t1; DROP TABLE t1; diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 7767abe43d0..78661b1bbc4 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -71,7 +71,8 @@ select "--- --position --" as ""; --enable_query_log --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ ---exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --position=239 $MYSQLD_DATADIR/master-bin.000002 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --position=330 $MYSQLD_DATADIR/master-bin.000002 + # These are tests for remote binlog. # They should return the same as previous test. @@ -107,7 +108,7 @@ select "--- --position --" as ""; --enable_query_log --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --replace_regex /SQL_LOAD_MB-[0-9]-[0-9]/SQL_LOAD_MB-#-#/ ---exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --read-from-remote-server --position=239 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQLTEST_VARDIR/tmp/ --read-from-remote-server --position=330 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 # Bug#7853 mysqlbinlog does not accept input from stdin --disable_query_log @@ -377,6 +378,68 @@ FLUSH LOGS; # We do not need the results, just make sure that mysqlbinlog does not crash --exec $MYSQL_BINLOG --hexdump --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 >/dev/null +# +# #46998 +# This test verifies if the 'BEGIN', 'COMMIT' and 'ROLLBACK' are output +# in regardless of database filtering +# + +RESET MASTER; +FLUSH LOGS; + +# The following three test cases were wrtten into binlog_transaction.000001 +# Test case1: Test if the 'BEGIN' and 'COMMIT' are output for the 'test' database +# in transaction1 base on innodb engine tables +# use test; +# create table t1(a int) engine= innodb; +# use mysql; +# create table t2(a int) engine= innodb; +# Transaction1 begin +# begin; +# use test; +# insert into t1 (a) values (1); +# use mysql; +# insert into t2 (a) values (1); +# commit; +# Transaction1 end + +# Test case2: Test if the 'BEGIN' and 'ROLLBACK' are output for the 'test' database +# in transaction2 base on innodb and myisam engine tables +# use test; +# create table t3(a int) engine= innodb; +# use mysql; +# create table t4(a int) engine= myisam; +# Transaction2 begin +# begin; +# use test; +# insert into t3 (a) values (2); +# use mysql; +# insert into t4 (a) values (2); +# rollback; +# Transaction2 end + +# Test case3: Test if the 'BEGIN' and 'COMMIT' are output for the 'test' database +# in transaction3 base on NDB engine tables +# use test; +# create table t5(a int) engine= NDB; +# use mysql; +# create table t6(a int) engine= NDB; +# Transaction3 begin +# begin; +# use test; +# insert into t5 (a) values (3); +# use mysql; +# insert into t6 (a) values (3); +# commit; +# Transaction3 end + +--echo # +--echo # Test if the 'BEGIN', 'ROLLBACK' and 'COMMIT' are output if the database specified is exist +--exec $MYSQL_BINLOG --database=test --short-form $MYSQLTEST_VARDIR/std_data/binlog_transaction.000001 +--echo # +--echo # Test if the 'BEGIN', 'ROLLBACK' and 'COMMIT' are output if the database specified is not exist +--exec $MYSQL_BINLOG --database=not_exist --short-form $MYSQLTEST_VARDIR/std_data/binlog_transaction.000001 + --echo End of 5.0 tests --echo End of 5.1 tests diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 578b2bf5c6c..bcf33aa8c27 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -853,16 +853,21 @@ while ($outer) eval SELECT '$outer = outer loop variable after dec' AS ""; } +# Test source in an if in a while which is false on 1st iteration +# Also test --error in same context let $outer= 2; # Number of outer loops +let $ifval= 0; # false 1st time while ($outer) { - eval SELECT '$outer = outer loop variable after while' AS ""; - - echo here is the sourced script; + echo outer=$outer ifval=$ifval; - eval SELECT '$outer = outer loop variable before dec' AS ""; + if ($ifval) { + --source $MYSQLTEST_VARDIR/tmp/sourced.inc + --error ER_NO_SUCH_TABLE + SELECT * from nowhere; + } dec $outer; - eval SELECT '$outer = outer loop variable after dec' AS ""; + inc $ifval; } @@ -1663,6 +1668,20 @@ EOF remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +# Test append_file within while +let $outer= 2; # Number of outer loops +while ($outer) +{ + append_file $MYSQLTEST_VARDIR/tmp/app_while.tmp; +These lines should be repeated, +if things work as expected +EOF + dec $outer; +} + +cat_file $MYSQLTEST_VARDIR/tmp/app_while.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/app_while.tmp; + # ---------------------------------------------------------------------------- # test for cat_file # ---------------------------------------------------------------------------- @@ -1710,10 +1729,6 @@ EOF --diff_files $MYSQLTEST_VARDIR/tmp/diff1.tmp $MYSQLTEST_VARDIR/tmp/diff2.tmp --diff_files $MYSQLTEST_VARDIR/tmp/diff2.tmp $MYSQLTEST_VARDIR/tmp/diff1.tmp -# Write the below commands to a intermediary file and execute them with -# mysqltest in --exec, since the output will vary depending on what "diff" -# is available it is sent to /dev/null ---write_file $MYSQLTEST_VARDIR/tmp/diff.test # Compare files that differ in size --error 2 --diff_files $MYSQLTEST_VARDIR/tmp/diff1.tmp $MYSQLTEST_VARDIR/tmp/diff3.tmp @@ -1725,13 +1740,6 @@ EOF --diff_files $MYSQLTEST_VARDIR/tmp/diff1.tmp $MYSQLTEST_VARDIR/tmp/diff4.tmp --error 1 --diff_files $MYSQLTEST_VARDIR/tmp/diff4.tmp $MYSQLTEST_VARDIR/tmp/diff1.tmp -exit; -EOF - -# Execute the above diffs, and send their output to /dev/null - only -# interesting to see that it returns correct error codes ---exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/diff.test > /dev/null 2>&1 - # Compare equal files, again... --diff_files $MYSQLTEST_VARDIR/tmp/diff1.tmp $MYSQLTEST_VARDIR/tmp/diff2.tmp @@ -1740,7 +1748,6 @@ EOF --remove_file $MYSQLTEST_VARDIR/tmp/diff2.tmp --remove_file $MYSQLTEST_VARDIR/tmp/diff3.tmp --remove_file $MYSQLTEST_VARDIR/tmp/diff4.tmp ---remove_file $MYSQLTEST_VARDIR/tmp/diff.test # ---------------------------------------------------------------------------- diff --git a/mysql-test/t/named_pipe.test b/mysql-test/t/named_pipe.test index e3dfd24bb52..e88fd8e1ef8 100644 --- a/mysql-test/t/named_pipe.test +++ b/mysql-test/t/named_pipe.test @@ -9,6 +9,11 @@ if (`SELECT '$nmp' != 'ON'`){ skip No named pipe support; } +# Connect using named pipe for testing +connect(pipe_con,localhost,root,,,,,PIPE); + # Source select test case -- source include/common-tests.inc +connection default; +disconnect pipe_con; diff --git a/mysql-test/t/not_partition.test b/mysql-test/t/not_partition.test index 78e6c7495cf..78ca44acf18 100644 --- a/mysql-test/t/not_partition.test +++ b/mysql-test/t/not_partition.test @@ -15,7 +15,7 @@ let $MYSQLD_DATADIR= `SELECT @@datadir`; # Bug#39893: Crash if select on a partitioned table, # when partitioning is disabled FLUSH TABLES; ---copy_file $MYSQLTEST_VARDIR/std_data_ln/parts/t1.frm $MYSQLD_DATADIR/test/t1.frm +--copy_file $MYSQLTEST_VARDIR/std_data/parts/t1.frm $MYSQLD_DATADIR/test/t1.frm SELECT * FROM t1; TRUNCATE TABLE t1; ANALYZE TABLE t1; diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index d1e40024733..8f672af40a3 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -375,4 +375,19 @@ INSERT INTO t1 VALUES(0); SELECT 1 FROM t1 GROUP BY (DATE(NULL)) WITH ROLLUP; DROP TABLE t1; +--echo # +--echo # Bug #48131: crash group by with rollup, distinct, +--echo # filesort, with temporary tables +--echo # + +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY); +INSERT INTO t1 VALUES (1), (2); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (100); + +SELECT a, b FROM t1, t2 GROUP BY a, b WITH ROLLUP; +SELECT DISTINCT b FROM t1, t2 GROUP BY a, b WITH ROLLUP; + +DROP TABLE t1, t2; + --echo End of 5.0 tests diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index e8887c07612..7d461df9cc8 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -1404,3 +1404,35 @@ SELECT DISTINCT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 0, 9; SELECT DISTINCT a FROM t1 WHERE b = 1 ORDER BY c DESC LIMIT 0, 9; DROP TABLE t1; + +--echo # +--echo # Bug #43029: FORCE INDEX FOR ORDER BY is ignored when join buffering +--echo # is used +--echo # + +CREATE TABLE t1 (a INT, b INT, KEY (a)); + +INSERT INTO t1 VALUES (0, NULL), (1, NULL), (2, NULL), (3, NULL); +INSERT INTO t1 SELECT a+4, b FROM t1; +INSERT INTO t1 SELECT a+8, b FROM t1; + +CREATE TABLE t2 (a INT, b INT); + +INSERT INTO t2 VALUES (0,NULL), (1,NULL), (2,NULL), (3,NULL), (4,NULL); +INSERT INTO t2 SELECT a+4, b FROM t2; + +--echo # shouldn't have "using filesort" +EXPLAIN +SELECT * FROM t1 FORCE INDEX FOR ORDER BY (a), t2 WHERE t1.a < 2 ORDER BY t1.a; + +--echo # should have "using filesort" +EXPLAIN +SELECT * FROM t1 USE INDEX FOR ORDER BY (a), t2 WHERE t1.a < 2 ORDER BY t1.a; + +--echo # should have "using filesort" +EXPLAIN +SELECT * FROM t1 FORCE INDEX FOR JOIN (a), t2 WHERE t1.a < 2 ORDER BY t1.a; + +DROP TABLE t1, t2; + +--echo End of 5.1 tests diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index c0e7cf2c66c..6fc0ba2a743 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -62,6 +62,19 @@ SHOW CREATE TABLE t1; DROP TABLE t1; # +# Bug#44059: rec_per_key on empty partition gives weird optimiser results +# +create table t1 (a int, b int, key(a)) +partition by list (a) +( partition p0 values in (1), + partition p1 values in (2)); +insert into t1 values (1,1),(2,1),(2,2),(2,3); +show indexes from t1; +analyze table t1; +show indexes from t1; +drop table t1; + +# # Bug#36001: Partitions: spelling and using some error messages # --error ER_FOREIGN_KEY_ON_PARTITIONED diff --git a/mysql-test/t/partition_csv.test b/mysql-test/t/partition_csv.test index dd2ef7c1d1f..44013dd4b0a 100644 --- a/mysql-test/t/partition_csv.test +++ b/mysql-test/t/partition_csv.test @@ -10,6 +10,8 @@ --source include/have_partition.inc --source include/have_csv.inc +call mtr.add_suppression("Failed to write to mysql.general_log"); + # # Bug#19307: Partitions: csv delete failure # = CSV engine crashes diff --git a/mysql-test/t/partition_innodb.test b/mysql-test/t/partition_innodb.test index 722fad2919e..6a70f20c7f3 100644 --- a/mysql-test/t/partition_innodb.test +++ b/mysql-test/t/partition_innodb.test @@ -6,6 +6,23 @@ drop table if exists t1; --enable_warnings # +# Bug#47029: Crash when reorganize partition with subpartition +# +create table t1 (a int not null, + b datetime not null, + primary key (a,b)) +engine=innodb +partition by range (to_days(b)) +subpartition by hash (a) +subpartitions 2 +( partition p0 values less than (to_days('2009-01-01')), + partition p1 values less than (to_days('2009-02-01')), + partition p2 values less than (to_days('2009-03-01')), + partition p3 values less than maxvalue); +alter table t1 reorganize partition p1,p2 into +( partition p2 values less than (to_days('2009-03-01'))); +drop table t1; +# # Bug#40595: Non-matching rows not released with READ-COMMITTED on tables # with partitions CREATE TABLE t1 (id INT PRIMARY KEY, data INT) ENGINE = InnoDB @@ -270,3 +287,15 @@ PARTITION BY RANGE (int_column) (PARTITION p1 VALUES LESS THAN (5)); show create table t1; drop table t1; + +# +# BUG#46483 - drop table of partitioned table may leave extraneous file +# Note: was only repeatable with InnoDB plugin +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB + PARTITION BY list(a) (PARTITION p1 VALUES IN (1)); +CREATE INDEX i1 ON t1 (a); +DROP TABLE t1; +let $MYSQLD_DATADIR= `SELECT @@datadir`; +# Before the fix it should show extra file like #sql-2405_2.par +--list_files $MYSQLD_DATADIR/test/ * diff --git a/mysql-test/t/partition_innodb_builtin.test b/mysql-test/t/partition_innodb_builtin.test new file mode 100644 index 00000000000..a9be41c7455 --- /dev/null +++ b/mysql-test/t/partition_innodb_builtin.test @@ -0,0 +1,67 @@ +--source include/have_partition.inc +--source include/have_innodb.inc +--source include/have_not_innodb_plugin.inc + +# +# Bug#32430 - show engine innodb status causes errors +# +SET NAMES utf8; +CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a)) +ENGINE=InnoDB +PARTITION BY RANGE (a) +SUBPARTITION BY HASH (a) +(PARTITION `p0``\""e` VALUES LESS THAN (100) + (SUBPARTITION `sp0``\""e`, + SUBPARTITION `sp1``\""e`), + PARTITION `p1``\""e` VALUES LESS THAN (MAXVALUE) + (SUBPARTITION `sp2``\""e`, + SUBPARTITION `sp3``\""e`)); +INSERT INTO `t``\""e` VALUES (0), (2), (6), (10), (14), (18), (22); +START TRANSACTION; +--echo # con1 +connect(con1,localhost,root,,); +SET NAMES utf8; +START TRANSACTION; +--echo # default connection +connection default; +UPDATE `t``\""e` SET a = 16 WHERE a = 0; +--echo # con1 +connection con1; +UPDATE `t``\""e` SET a = 8 WHERE a = 22; +let $id_1= `SELECT CONNECTION_ID()`; +SEND; +UPDATE `t``\""e` SET a = 12 WHERE a = 0; +--echo # default connection +connection default; +let $wait_timeout= 2; +let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE ID = $id_1 AND STATE = 'Searching rows for update'; +--source include/wait_condition.inc +#--echo # tested wait condition $wait_condition_reps times +--error ER_LOCK_DEADLOCK +UPDATE `t``\""e` SET a = 4 WHERE a = 22; +--echo # First table reported in 'SHOW ENGINE InnoDB STATUS' +# RECORD LOCKS space id 0 page no 50 n bits 80 index `PRIMARY` in \ +# Database `test`, Table `t1`, Partition `p0`, Subpartition `sp0` \ +# trx id 0 775 +# NOTE: replace_regex is very slow on match copy/past '(.*)' regex's +# on big texts, removing a lot of text before + after makes it much faster. +#/.*in (.*) trx.*/\1/ +--replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // +SHOW ENGINE InnoDB STATUS; +set @old_sql_mode = @@sql_mode; +set sql_mode = 'ANSI_QUOTES'; +# INNODB_LOCKS only exists in innodb_plugin +#SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; +--replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // +SHOW ENGINE InnoDB STATUS; +set @@sql_mode = @old_sql_mode; +--echo # con1 +connection con1; +REAP; +ROLLBACK; +disconnect con1; +--echo # default connection +connection default; +DROP TABLE `t``\""e`; +SET NAMES DEFAULT; diff --git a/mysql-test/t/partition_innodb_plugin.test b/mysql-test/t/partition_innodb_plugin.test new file mode 100644 index 00000000000..fed8c96424a --- /dev/null +++ b/mysql-test/t/partition_innodb_plugin.test @@ -0,0 +1,75 @@ +--source include/have_partition.inc +--source include/have_innodb.inc +--source suite/innodb/include/have_innodb_plugin.inc + +# +# Bug#32430 - show engine innodb status causes errors +# +SET NAMES utf8; +CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a)) +ENGINE=InnoDB +PARTITION BY RANGE (a) +SUBPARTITION BY HASH (a) +(PARTITION `p0``\""e` VALUES LESS THAN (100) + (SUBPARTITION `sp0``\""e`, + SUBPARTITION `sp1``\""e`), + PARTITION `p1``\""e` VALUES LESS THAN (MAXVALUE) + (SUBPARTITION `sp2``\""e`, + SUBPARTITION `sp3``\""e`)); +INSERT INTO `t``\""e` VALUES (0), (2), (6), (10), (14), (18), (22); +START TRANSACTION; +--echo # con1 +connect(con1,localhost,root,,); +SET NAMES utf8; +START TRANSACTION; +--echo # default connection +connection default; +UPDATE `t``\""e` SET a = 16 WHERE a = 0; +--echo # con1 +connection con1; +UPDATE `t``\""e` SET a = 8 WHERE a = 22; +let $id_1= `SELECT CONNECTION_ID()`; +SEND; +UPDATE `t``\""e` SET a = 12 WHERE a = 0; +--echo # default connection +connection default; +let $wait_timeout= 2; +let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE ID = $id_1 AND STATE = 'Searching rows for update'; +--source include/wait_condition.inc +#--echo # tested wait condition $wait_condition_reps times +# INNODB_LOCKS only exists in innodb_plugin +--sorted_result +SELECT lock_table, COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS +GROUP BY lock_table; +set @old_sql_mode = @@sql_mode; +set sql_mode = 'ANSI_QUOTES'; +--sorted_result +SELECT lock_table, COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS +GROUP BY lock_table; +set @@sql_mode = @old_sql_mode; +--error ER_LOCK_DEADLOCK +UPDATE `t``\""e` SET a = 4 WHERE a = 22; +--echo # First table reported in 'SHOW ENGINE InnoDB STATUS' +# RECORD LOCKS space id 0 page no 50 n bits 80 index `PRIMARY` in \ +# Database `test`, Table `t1`, Partition `p0`, Subpartition `sp0` \ +# trx id 0 775 +# NOTE: replace_regex is very slow on match copy/past '(.*)' regex's +# on big texts, removing a lot of text before + after makes it much faster. +#/.*in (.*) trx.*/\1/ +--replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // +SHOW ENGINE InnoDB STATUS; +set @old_sql_mode = @@sql_mode; +set sql_mode = 'ANSI_QUOTES'; +--replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // +SHOW ENGINE InnoDB STATUS; +set @@sql_mode = @old_sql_mode; +--echo # con1 +connection con1; +REAP; +ROLLBACK; +disconnect con1; +--echo # default connection +connection default; +DROP TABLE `t``\""e`; +SET NAMES DEFAULT; diff --git a/mysql-test/t/partition_open_files_limit-master.opt b/mysql-test/t/partition_open_files_limit-master.opt new file mode 100644 index 00000000000..4c1ed0c3da3 --- /dev/null +++ b/mysql-test/t/partition_open_files_limit-master.opt @@ -0,0 +1 @@ +--open-files-limit=5 --max_connections=2 --table_open_cache=1 diff --git a/mysql-test/t/partition_open_files_limit.test b/mysql-test/t/partition_open_files_limit.test new file mode 100644 index 00000000000..e62ebd0ade7 --- /dev/null +++ b/mysql-test/t/partition_open_files_limit.test @@ -0,0 +1,26 @@ +--source include/have_partition.inc + +--disable_warnings +DROP TABLE IF EXISTS `t1`; +--enable_warnings + +# On some platforms the lowest possible open_files_limit is too high... +let $max_open_files_limit= `SELECT @@open_files_limit > 511`; +if ($max_open_files_limit) +{ + skip Need open_files_limit to be lower than 512; +} + +# +--echo # Bug#46922: crash when adding partitions and open_files_limit is reached +# +CREATE TABLE t1 (a INT PRIMARY KEY) +ENGINE=MyISAM PARTITION BY KEY () PARTITIONS 1; +INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11); +--echo # if the bug exists, then crash will happen here +--replace_regex /file '.*'/file '<partition file>'/ +--error 23 +ALTER TABLE t1 ADD PARTITION PARTITIONS 511; +--sorted_result +SELECT * FROM t1; +DROP TABLE t1; diff --git a/mysql-test/t/plugin.test b/mysql-test/t/plugin.test index 7fc62b445c9..788a7b336ef 100644 --- a/mysql-test/t/plugin.test +++ b/mysql-test/t/plugin.test @@ -1,3 +1,4 @@ +--source include/not_windows_embedded.inc --source include/have_example_plugin.inc CREATE TABLE t1(a int) ENGINE=EXAMPLE; diff --git a/mysql-test/t/plugin_load.test b/mysql-test/t/plugin_load.test index 8555247dd71..97b2afbe219 100644 --- a/mysql-test/t/plugin_load.test +++ b/mysql-test/t/plugin_load.test @@ -1,3 +1,4 @@ +--source include/not_windows_embedded.inc --source include/have_example_plugin.inc SELECT @@global.example_enum_var = 'e2'; diff --git a/mysql-test/t/ps_not_windows.test b/mysql-test/t/ps_not_windows.test index 1dceacd73da..0ab08b59f1e 100644 --- a/mysql-test/t/ps_not_windows.test +++ b/mysql-test/t/ps_not_windows.test @@ -2,7 +2,7 @@ --source include/not_embedded.inc # Non-windows specific ps tests. --source include/not_windows.inc -# Requires ability to install plugins. +# requires dynamic loading --source include/have_dynamic_loading.inc # diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 9a1547fa3d4..3d9045d3aa6 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -1294,7 +1294,7 @@ SET GLOBAL query_cache_size= default; # Bug #31157: Crash when select+order by the avg of some field within the # group by # - +SET GLOBAL query_cache_size=1024*1024*512; CREATE TABLE t1 (a ENUM('rainbow')); INSERT INTO t1 VALUES (),(),(),(),(); SELECT 1 FROM t1 GROUP BY (SELECT 1 FROM t1 ORDER BY AVG(LAST_INSERT_ID())); @@ -1305,6 +1305,7 @@ INSERT INTO t1 SET a = 'aaaa'; SELECT 1 FROM t1 GROUP BY (SELECT LAST_INSERT_ID() FROM t1 ORDER BY MIN(a) ASC LIMIT 1); DROP TABLE t1; +SET GLOBAL query_cache_size= default; --echo End of 5.1 tests diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index e1411e7fd46..3a845471cd0 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1046,3 +1046,218 @@ explain select * from t2 where a=1000 and b<11; drop table t1, t2; +# +# Bug#42846: wrong result returned for range scan when using covering index +# +CREATE TABLE t1( a INT, b INT, KEY( a, b ) ); + +CREATE TABLE t2( a INT, b INT, KEY( a, b ) ); + +CREATE TABLE t3( a INT, b INT, KEY( a, b ) ); + +INSERT INTO t1( a, b ) +VALUES (0, 1), (1, 2), (1, 4), (2, 3), (5, 0), (9, 7); + +INSERT INTO t2( a, b ) +VALUES ( 1, 1), ( 2, 1), ( 3, 1), ( 4, 1), ( 5, 1), + ( 6, 1), ( 7, 1), ( 8, 1), ( 9, 1), (10, 1), + (11, 1), (12, 1), (13, 1), (14, 1), (15, 1), + (16, 1), (17, 1), (18, 1), (19, 1), (20, 1); + +INSERT INTO t2 SELECT a, 2 FROM t2 WHERE b = 1; +INSERT INTO t2 SELECT a, 3 FROM t2 WHERE b = 1; + +# To make range scan compelling to the optimizer +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t2 SELECT -1, -1 FROM t2; +INSERT INTO t2 SELECT -1, -1 FROM t2; + +INSERT INTO t3 +VALUES (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), + (6, 0), (7, 0), (8, 0), (9, 0), (10, 0); + +# To make range scan compelling to the optimizer +INSERT INTO t3 SELECT * FROM t3 WHERE a = 10; +INSERT INTO t3 SELECT * FROM t3 WHERE a = 10; + + +# +# Problem#1 Test queries. Will give missing results unless Problem#1 is fixed. +# With one exception, they are independent of Problem#2. +# +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 < a AND b = 3 OR +3 <= a; + +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 < a AND b = 3 OR +3 <= a; + +# Query below: Tests both Problem#1 and Problem#2 (EXPLAIN differs as well) +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 <= a AND b = 3 OR +3 <= a; + +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a < 5 OR +5 <= a AND b = 3 OR +3 <= a; + +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +5 <= a AND b = 3 OR +3 <= a; + +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +5 <= a AND b = 3 OR +3 <= a; + +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +3 <= a; + +EXPLAIN +SELECT * FROM t1 WHERE +3 <= a AND a <= 5 OR +3 <= a; + +# +# Problem#2 Test queries. +# These queries will give missing results if Problem#1 is fixed. +# But Problem#1 also hides this bug. +# +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 1 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; + +EXPLAIN +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 1 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; + +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 2 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; + +EXPLAIN +SELECT * FROM t2 WHERE +5 <= a AND a < 10 AND b = 2 OR +15 <= a AND a < 20 AND b = 3 +OR +1 <= a AND b = 1; + +SELECT * FROM t3 WHERE +5 <= a AND a < 10 AND b = 3 OR +a < 5 OR +a < 10; + +EXPLAIN +SELECT * FROM t3 WHERE +5 <= a AND a < 10 AND b = 3 OR +a < 5 OR +a < 10; + +DROP TABLE t1, t2, t3; + +--echo # +--echo # Bug #47123: Endless 100% CPU loop with STRAIGHT_JOIN +--echo # + +CREATE TABLE t1(a INT, KEY(a)); +INSERT INTO t1 VALUES (1), (NULL); +SELECT * FROM t1 WHERE a <> NULL and (a <> NULL or a <= NULL); +DROP TABLE t1; + +--echo # +--echo # Bug#47925: regression of range optimizer and date comparison in 5.1.39! +--echo # +CREATE TABLE t1 ( a DATE, KEY ( a ) ); +CREATE TABLE t2 ( a DATETIME, KEY ( a ) ); + +--echo # Make optimizer choose range scan +INSERT INTO t1 VALUES ('2009-09-22'), ('2009-09-22'), ('2009-09-22'); +INSERT INTO t1 VALUES ('2009-09-23'), ('2009-09-23'), ('2009-09-23'); + +INSERT INTO t2 VALUES ('2009-09-22 12:00:00'), ('2009-09-22 12:00:00'), + ('2009-09-22 12:00:00'); +INSERT INTO t2 VALUES ('2009-09-23 12:00:00'), ('2009-09-23 12:00:00'), + ('2009-09-23 12:00:00'); + +--echo # DATE vs DATE +--replace_column 1 X 2 X 3 X 7 X 8 X 9 X 10 X +EXPLAIN +SELECT * FROM t1 WHERE a >= '2009/09/23'; +SELECT * FROM t1 WHERE a >= '2009/09/23'; +SELECT * FROM t1 WHERE a >= '20090923'; +SELECT * FROM t1 WHERE a >= 20090923; +SELECT * FROM t1 WHERE a >= '2009-9-23'; +SELECT * FROM t1 WHERE a >= '2009.09.23'; +SELECT * FROM t1 WHERE a >= '2009:09:23'; + +--echo # DATE vs DATETIME +--replace_column 1 X 2 X 3 X 7 X 8 X 9 X 10 X +EXPLAIN +SELECT * FROM t2 WHERE a >= '2009/09/23'; +SELECT * FROM t2 WHERE a >= '2009/09/23'; +SELECT * FROM t2 WHERE a >= '2009/09/23'; +SELECT * FROM t2 WHERE a >= '20090923'; +SELECT * FROM t2 WHERE a >= 20090923; +SELECT * FROM t2 WHERE a >= '2009-9-23'; +SELECT * FROM t2 WHERE a >= '2009.09.23'; +SELECT * FROM t2 WHERE a >= '2009:09:23'; + +--echo # DATETIME vs DATETIME +--replace_column 1 X 2 X 3 X 7 X 8 X 9 X 10 X +EXPLAIN +SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00'; +SELECT * FROM t2 WHERE a >= '2009/09/23 12:00:00'; +SELECT * FROM t2 WHERE a >= '20090923120000'; +SELECT * FROM t2 WHERE a >= 20090923120000; +SELECT * FROM t2 WHERE a >= '2009-9-23 12:00:00'; +SELECT * FROM t2 WHERE a >= '2009.09.23 12:00:00'; +SELECT * FROM t2 WHERE a >= '2009:09:23 12:00:00'; + +--echo # DATETIME vs DATE +--replace_column 1 X 2 X 3 X 7 X 8 X 9 X 10 X +EXPLAIN +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +SELECT * FROM t1 WHERE a >= '2009/09/23 00:00:00'; +SELECT * FROM t1 WHERE a >= '20090923000000'; +SELECT * FROM t1 WHERE a >= 20090923000000; +SELECT * FROM t1 WHERE a >= '2009-9-23 00:00:00'; +SELECT * FROM t1 WHERE a >= '2009.09.23 00:00:00'; +SELECT * FROM t1 WHERE a >= '2009:09:23 00:00:00'; + +--echo # Test of the new get_date_from_str implementation +--echo # Behavior differs slightly between the trunk and mysql-pe. +--echo # The former may give errors for the truncated values, while the latter +--echo # gives warnings. The purpose of this test is not to interfere, and only +--echo # preserve existing behavior. +SELECT str_to_date('2007-10-00', '%Y-%m-%d') >= '' AND + str_to_date('2007-10-00', '%Y-%m-%d') <= '2007/10/20'; + +SELECT str_to_date('2007-20-00', '%Y-%m-%d') >= '2007/10/20' AND + str_to_date('2007-20-00', '%Y-%m-%d') <= ''; + +SELECT str_to_date('2007-10-00', '%Y-%m-%d') BETWEEN '' AND '2007/10/20'; +SELECT str_to_date('2007-20-00', '%Y-%m-%d') BETWEEN '2007/10/20' AND ''; + +SELECT str_to_date('', '%Y-%m-%d'); + +DROP TABLE t1, t2; + +--echo End of 5.1 tests diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 7d3785ecccc..51f0cd73374 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -3739,7 +3739,40 @@ EXPLAIN EXTENDED SELECT a, b FROM t1 WHERE a > 1 AND a = b LIMIT 2; EXPLAIN EXTENDED SELECT a, b FROM t1 WHERE a > 1 AND b = a LIMIT 2; DROP TABLE t1; + + +--echo # +--echo # Bug#47019: Assertion failed: 0, file .\rt_mbr.c, line 138 when +--echo # forcing a spatial index +--echo # +CREATE TABLE t1(a LINESTRING NOT NULL, SPATIAL KEY(a)); +INSERT INTO t1 VALUES + (GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')), + (GEOMFROMTEXT('LINESTRING(-1 -1, 1 -1, -1 -1, -1 1, 1 1)')); +EXPLAIN SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2; +SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2; +EXPLAIN SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2 FORCE INDEX(a); +SELECT 1 FROM t1 NATURAL LEFT JOIN t1 AS t2 FORCE INDEX(a); +DROP TABLE t1; + + +--echo # +--echo # Bug #48291 : crash with row() operator,select into @var, and +--echo # subquery returning multiple rows +--echo # + +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (2),(3); + +--echo # Should not crash +--error ER_SUBQUERY_NO_1_ROW +SELECT 1 FROM t1 WHERE a <> 1 AND NOT +ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1)) +INTO @var0; + +DROP TABLE t1; + --echo End of 5.0 tests # diff --git a/mysql-test/t/sp-bugs.test b/mysql-test/t/sp-bugs.test new file mode 100644 index 00000000000..7b94e65a5e9 --- /dev/null +++ b/mysql-test/t/sp-bugs.test @@ -0,0 +1,61 @@ +# Test file for stored procedure bugfixes + +--echo # +--echo # Bug #47412: Valgrind warnings / user can read uninitalized memory +--echo # using SP variables +--echo # + +CREATE SCHEMA testdb; +USE testdb; +DELIMITER |; +CREATE FUNCTION f2 () RETURNS INTEGER +BEGIN + DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' SET @aux = 1; + RETURN f_not_exists () ; +END| +CREATE PROCEDURE p3 ( arg1 VARCHAR(32) ) +BEGIN + CALL p_not_exists ( ); +END| +DELIMITER ;| +--echo # should not return valgrind warnings +--error ER_SP_DOES_NOT_EXIST +CALL p3 ( f2 () ); + +DROP SCHEMA testdb; + +CREATE SCHEMA testdb; +USE testdb; +DELIMITER |; +CREATE FUNCTION f2 () RETURNS INTEGER +BEGIN + DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' SET @aux = 1; + RETURN f_not_exists () ; +END| +CREATE PROCEDURE p3 ( arg2 INTEGER ) +BEGIN + CALL p_not_exists ( ); +END| +DELIMITER ;| +--echo # should not return valgrind warnings +--error ER_SP_DOES_NOT_EXIST +CALL p3 ( f2 () ); + +DROP SCHEMA testdb; + +CREATE SCHEMA testdb; +USE testdb; +DELIMITER |; +CREATE FUNCTION f2 () RETURNS INTEGER +BEGIN + DECLARE CONTINUE HANDLER FOR SQLSTATE '42000' SET @aux = 1; + RETURN f_not_exists () ; +END| +DELIMITER ;| +--echo # should not return valgrind warnings +SELECT f2 (); + +DROP SCHEMA testdb; + + +--echo End of 5.1 tests diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 66b960c938f..18a4a117939 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -2448,3 +2448,27 @@ SELECT AVG (a) FROM t1 WHERE b = 999999; --error ER_SP_DOES_NOT_EXIST SELECT non_existent (a) FROM t1 WHERE b = 999999; DROP TABLE t1; + +--echo # +--echo # Bug #47788: Crash in TABLE_LIST::hide_view_error on UPDATE + VIEW + +--echo # SP + MERGE + ALTER +--echo # + +CREATE TABLE t1 (pk INT, b INT, KEY (b)); +CREATE ALGORITHM = TEMPTABLE VIEW v1 AS SELECT * FROM t1; + +CREATE PROCEDURE p1 (a int) UPDATE IGNORE v1 SET b = a; + +--error ER_NON_UPDATABLE_TABLE +CALL p1(5); + +ALTER TABLE t1 CHANGE COLUMN b b2 INT; + +--error ER_VIEW_INVALID +CALL p1(7); + +DROP PROCEDURE p1; +DROP VIEW v1; +DROP TABLE t1; + +--echo End of 5.1 tests diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 5eeac457958..44c4556340e 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -8242,6 +8242,28 @@ while ($tab_count) DROP PROCEDURE p1; DROP TABLE t1; + +--echo # +--echo # Bug #46629: Item_in_subselect::val_int(): Assertion `0' +--echo # on subquery inside a SP +--echo # +CREATE TABLE t1(a INT); +CREATE TABLE t2(a INT, b INT PRIMARY KEY); + +DELIMITER |; +CREATE PROCEDURE p1 () +BEGIN + SELECT a FROM t1 A WHERE A.b IN (SELECT b FROM t2 AS B); +END| +DELIMITER ;| +--error ER_BAD_FIELD_ERROR +CALL p1; +--error ER_BAD_FIELD_ERROR +CALL p1; +DROP PROCEDURE p1; +DROP TABLE t1, t2; + + --echo # ------------------------------------------------------------------ --echo # -- End of 5.1 tests --echo # ------------------------------------------------------------------ diff --git a/mysql-test/t/status-master.opt b/mysql-test/t/status-master.opt new file mode 100644 index 00000000000..eb3bb4fe50d --- /dev/null +++ b/mysql-test/t/status-master.opt @@ -0,0 +1 @@ +--log-output=table,file diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index ead7c89d1c0..2391554dccd 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -30,7 +30,7 @@ SELECT 1 IN (SELECT 1); SELECT 1 FROM (SELECT 1 as a) b WHERE 1 IN (SELECT (SELECT a)); -- error ER_WRONG_USAGE select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1)); --- error ER_WRONG_USAGE +-- error ER_WRONG_PARAMETERS_TO_PROCEDURE SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1)); -- error ER_BAD_FIELD_ERROR SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL; @@ -3554,4 +3554,19 @@ where v in(select v where t1.g=t2.g) is unknown; drop table t1, t2; +# +# Bug #31157: Crash when select+order by the avg of some field within the +# group by +# +CREATE TABLE t1 (a ENUM('rainbow')); +INSERT INTO t1 VALUES (),(),(),(),(); +SELECT 1 FROM t1 GROUP BY (SELECT 1 FROM t1 ORDER BY AVG(LAST_INSERT_ID())); +DROP TABLE t1; +CREATE TABLE t1 (a LONGBLOB); +INSERT INTO t1 SET a = 'aaaa'; +INSERT INTO t1 SET a = 'aaaa'; +SELECT 1 FROM t1 GROUP BY + (SELECT LAST_INSERT_ID() FROM t1 ORDER BY MIN(a) ASC LIMIT 1); +DROP TABLE t1; + --echo End of 5.1 tests. diff --git a/mysql-test/t/subselect3.test b/mysql-test/t/subselect3.test index ee90fb9ff52..8d403279a48 100644 --- a/mysql-test/t/subselect3.test +++ b/mysql-test/t/subselect3.test @@ -730,3 +730,69 @@ where from t4, t5 limit 2)); drop table t0, t1, t2, t3, t4, t5; + +--echo # +--echo # BUG#48177 - SELECTs with NOT IN subqueries containing NULL +--echo # values return too many records +--echo # + +CREATE TABLE t1 ( + i1 int DEFAULT NULL, + i2 int DEFAULT NULL +) ; + +INSERT INTO t1 VALUES (1, NULL); +INSERT INTO t1 VALUES (2, 3); +INSERT INTO t1 VALUES (4, NULL); +INSERT INTO t1 VALUES (4, 0); +INSERT INTO t1 VALUES (NULL, NULL); + +CREATE TABLE t2 ( + i1 int DEFAULT NULL, + i2 int DEFAULT NULL +) ; + +INSERT INTO t2 VALUES (4, NULL); +INSERT INTO t2 VALUES (5, 0); + +--echo +--echo Data in t1 +SELECT i1, i2 FROM t1; + +--echo +--echo Data in subquery (should be filtered out) +SELECT i1, i2 FROM t2 ORDER BY i1; + +FLUSH STATUS; + +--echo +SELECT i1, i2 +FROM t1 +WHERE (i1, i2) + NOT IN (SELECT i1, i2 FROM t2); + +--echo +--echo # Check that the subquery only has to be evaluated once +--echo # for all-NULL values even though there are two (NULL,NULL) records +--echo # Baseline: +SHOW STATUS LIKE '%Handler_read_rnd_next'; + +--echo +INSERT INTO t1 VALUES (NULL, NULL); +FLUSH STATUS; + +--echo +SELECT i1, i2 +FROM t1 +WHERE (i1, i2) + NOT IN (SELECT i1, i2 FROM t2); + +--echo +--echo # Handler_read_rnd_next should be one more than baseline +--echo # (read record from t1, but do not read from t2) +SHOW STATUS LIKE '%Handler_read_rnd_next'; + + +DROP TABLE t1,t2; + +--echo End of 5.1 tests diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test new file mode 100644 index 00000000000..440eca22828 --- /dev/null +++ b/mysql-test/t/subselect4.test @@ -0,0 +1,64 @@ +# General purpose bug fix tests go here : subselect.test too large + + +--echo # +--echo # Bug #46791: Assertion failed:(table->key_read==0),function unknown +--echo # function,file sql_base.cc +--echo # + +CREATE TABLE t1 (a INT, b INT, KEY(a)); +INSERT INTO t1 VALUES (1,1),(2,2); +CREATE TABLE t2 LIKE t1; +INSERT INTO t2 VALUES (1,1),(2,2); +CREATE TABLE t3 LIKE t1; + +--echo # should have 1 impossible where and 2 dependent subqueries +EXPLAIN +SELECT 1 FROM t1 +WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE 1 = (SELECT MIN(t2.b) FROM t3)) +ORDER BY count(*); + +--echo # should not crash the next statement +SELECT 1 FROM t1 +WHERE NOT EXISTS (SELECT 1 FROM t2 WHERE 1 = (SELECT MIN(t2.b) FROM t3)) +ORDER BY count(*); + +--echo # should not crash: the crash is caused by the previous statement +SELECT 1; + +DROP TABLE t1,t2,t3; + +--echo # +--echo # Bug #47106: Crash / segfault on adding EXPLAIN to a non-crashing +--echo # query +--echo # + +CREATE TABLE t1 ( + a INT, + b INT, + PRIMARY KEY (a), + KEY b (b) +); +INSERT INTO t1 VALUES (1, 1), (2, 1); + +CREATE TABLE t2 LIKE t1; +INSERT INTO t2 SELECT * FROM t1; + +CREATE TABLE t3 LIKE t1; +INSERT INTO t3 SELECT * FROM t1; + +--echo # Should not crash. +--echo # Should have 1 impossible where and 2 dependent subqs. +EXPLAIN +SELECT + (SELECT 1 FROM t1,t2 WHERE t2.b > t3.b) +FROM t3 WHERE 1 = 0 GROUP BY 1; + +--echo # should return 0 rows +SELECT + (SELECT 1 FROM t1,t2 WHERE t2.b > t3.b) +FROM t3 WHERE 1 = 0 GROUP BY 1; + +DROP TABLE t1,t2,t3; + +--echo End of 5.0 tests. diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test index dc5120db430..530389b3ab9 100644 --- a/mysql-test/t/type_bit.test +++ b/mysql-test/t/type_bit.test @@ -397,6 +397,17 @@ insert into t2bit7 values (b'110011011111111'); select bin(a1) from t1bit7, t2bit7 where t1bit7.a1=t2bit7.b1; drop table t1bit7, t2bit7; + +--echo # +--echo # Bug42803: Field_bit does not have unsigned_flag field, +--echo # can lead to bad memory access +--echo # +CREATE TABLE t1 (a BIT(7), b BIT(9), KEY(a, b)); +INSERT INTO t1 VALUES(0, 0), (5, 3), (5, 6), (6, 4), (7, 0); +EXPLAIN SELECT a+0, b+0 FROM t1 WHERE a > 4 and b < 7 ORDER BY 2; +DROP TABLE t1; + + --echo End of 5.0 tests # diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index 65bafaae77e..cd3c3f81510 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -1286,137 +1286,3 @@ CREATE TABLE t1 SELECT 1 % .1234567891234567891234567891234567891234567891234567 DESCRIBE t1; SELECT my_col FROM t1; DROP TABLE t1; - ---echo # ---echo # Bug#45261: Crash, stored procedure + decimal ---echo # - ---disable_warnings -DROP TABLE IF EXISTS t1; ---enable_warnings - -CREATE TABLE t1 SELECT - /* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001 - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001. - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.1 /* 1 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001 - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 40 */ 1000000000000000000000000000000000000001.1000000000000000000000000000000000000001 /* 40 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 1 */ 1.10000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 80 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 1 */ 1.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - .100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 45 */ 123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345 /* 45 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 65 */ 12345678901234567890123456789012345678901234567890123456789012345.1 /* 1 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - /* 66 */ 123456789012345678901234567890123456789012345678901234567890123456.1 /* 1 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT - .123456789012345678901234567890123456789012345678901234567890123456 /* 66 */ - AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 AS SELECT 123.1234567890123456789012345678901 /* 31 */ AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 SELECT 1.1 + CAST(1 AS DECIMAL(65,30)) AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; - ---echo # ---echo # Test that the integer and decimal parts are properly calculated. ---echo # - -CREATE TABLE t1 (a DECIMAL(30,30)); -INSERT INTO t1 VALUES (0.1),(0.2),(0.3); -CREATE TABLE t2 SELECT MIN(a + 0.0000000000000000000000000000001) AS c1 FROM t1; -DESC t2; -DROP TABLE t1,t2; - -CREATE TABLE t1 (a DECIMAL(30,30)); -INSERT INTO t1 VALUES (0.1),(0.2),(0.3); -CREATE TABLE t2 SELECT IFNULL(a + 0.0000000000000000000000000000001, NULL) AS c1 FROM t1; -DESC t2; -DROP TABLE t1,t2; - -CREATE TABLE t1 (a DECIMAL(30,30)); -INSERT INTO t1 VALUES (0.1),(0.2),(0.3); -CREATE TABLE t2 SELECT CASE a WHEN 0.1 THEN 0.0000000000000000000000000000000000000000000000000000000000000000001 END AS c1 FROM t1; -DESC t2; -DROP TABLE t1,t2; - ---echo # ---echo # Test that variables get maximum precision. ---echo # - -SET @decimal= 1.1; -CREATE TABLE t1 SELECT @decimal AS c1; -DESC t1; -SELECT * FROM t1; -DROP TABLE t1; diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test index e9ae1a31079..7bf252040e5 100644 --- a/mysql-test/t/udf.test +++ b/mysql-test/t/udf.test @@ -436,4 +436,16 @@ SELECT * FROM t2 WHERE a = sequence(); DROP FUNCTION sequence; DROP TABLE t1,t2; +--echo # +--echo # Bug#46259: 5.0.83 -> 5.1.36, query doesn't work +--echo # +CREATE TABLE t1 ( a INT ); + +INSERT INTO t1 VALUES (1), (2), (3); + +SELECT IF( a = 1, a, a ) AS `b` FROM t1 ORDER BY field( `b` + 1, 1 ); +SELECT IF( a = 1, a, a ) AS `b` FROM t1 ORDER BY field( `b`, 1 ); + +DROP TABLE t1; + --echo End of 5.0 tests. diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index 7d56df259ba..02e8763a630 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -452,3 +452,18 @@ DROP TABLE t1; DROP FUNCTION f1; --echo End of 5.0 tests + +--echo # +--echo # Bug #47919 assert in open_table during ALTER temporary table +--echo # + +CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT, PRIMARY KEY (f1)); +CREATE TEMPORARY TABLE t2 LIKE t1; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (1); + +ALTER TABLE t2 COMMENT = 'ABC'; +UPDATE t2, t1 SET t2.f1 = 2, t1.f1 = 9; +ALTER TABLE t2 COMMENT = 'DEF'; + +DROP TABLE t1, t2; diff --git a/mysql-test/t/upgrade.test b/mysql-test/t/upgrade.test index d571a2efc7c..e390e8a1253 100644 --- a/mysql-test/t/upgrade.test +++ b/mysql-test/t/upgrade.test @@ -124,6 +124,8 @@ with_check_option=0 timestamp=2009-04-10 11:53:37 create-version=1 source=select f1 from `a-b-c`.t1 a, information_schema.tables b\nwhere a.f1 = b.table_name +client_cs_name=utf8 +connection_cl_name=utf8_general_ci EOF show databases like '%a-b-c%'; diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index 824c67d867e..175468db702 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -1382,6 +1382,153 @@ DROP VIEW test.v3; DROP USER mysqluser1@localhost; USE test; +--echo # +--echo # Bug#35996: SELECT + SHOW VIEW should be enough to display view +--echo # definition +--echo # +-- source include/not_embedded.inc +CREATE USER mysqluser1@localhost; +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; +GRANT USAGE, SELECT, CREATE VIEW, SHOW VIEW +ON mysqltest2.* TO mysqluser1@localhost; + +USE mysqltest1; + +CREATE TABLE t1( a INT ); +CREATE TABLE t2( a INT, b INT ); +CREATE FUNCTION f1() RETURNS INT RETURN 1; +CREATE VIEW v1 AS SELECT 1 AS a; +CREATE VIEW v2 AS SELECT 1 AS a, 2 AS b; + +GRANT SELECT ON TABLE t1 TO mysqluser1@localhost; +GRANT SELECT (a, b) ON TABLE t2 TO mysqluser1@localhost; +GRANT EXECUTE ON FUNCTION f1 TO mysqluser1@localhost; +GRANT SELECT ON TABLE v1 TO mysqluser1@localhost; +GRANT SELECT (a, b) ON TABLE v2 TO mysqluser1@localhost; + +CREATE VIEW v_t1 AS SELECT * FROM t1; +CREATE VIEW v_t2 AS SELECT * FROM t2; +CREATE VIEW v_f1 AS SELECT f1() AS a; +CREATE VIEW v_v1 AS SELECT * FROM v1; +CREATE VIEW v_v2 AS SELECT * FROM v2; + +GRANT SELECT, SHOW VIEW ON v_t1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_t2 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_f1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_v1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_v2 TO mysqluser1@localhost; + +--connect (connection1, localhost, mysqluser1,, mysqltest2) +CREATE VIEW v_mysqluser1_t1 AS SELECT * FROM mysqltest1.t1; +CREATE VIEW v_mysqluser1_t2 AS SELECT * FROM mysqltest1.t2; +CREATE VIEW v_mysqluser1_f1 AS SELECT mysqltest1.f1() AS a; +CREATE VIEW v_mysqluser1_v1 AS SELECT * FROM mysqltest1.v1; +CREATE VIEW v_mysqluser1_v2 AS SELECT * FROM mysqltest1.v2; + +SHOW CREATE VIEW mysqltest1.v_t1; +SHOW CREATE VIEW mysqltest1.v_t2; +SHOW CREATE VIEW mysqltest1.v_f1; +SHOW CREATE VIEW mysqltest1.v_v1; +SHOW CREATE VIEW mysqltest1.v_v2; + +SHOW CREATE VIEW v_mysqluser1_t1; +SHOW CREATE VIEW v_mysqluser1_t2; +SHOW CREATE VIEW v_mysqluser1_f1; +SHOW CREATE VIEW v_mysqluser1_v1; +SHOW CREATE VIEW v_mysqluser1_v2; + +--connection default +REVOKE SELECT ON TABLE t1 FROM mysqluser1@localhost; +REVOKE SELECT (a) ON TABLE t2 FROM mysqluser1@localhost; +REVOKE EXECUTE ON FUNCTION f1 FROM mysqluser1@localhost; +REVOKE SELECT ON TABLE v1 FROM mysqluser1@localhost; + +--connection connection1 +SHOW CREATE VIEW mysqltest1.v_t1; +SHOW CREATE VIEW mysqltest1.v_t2; +SHOW CREATE VIEW mysqltest1.v_f1; +SHOW CREATE VIEW mysqltest1.v_v1; +SHOW CREATE VIEW mysqltest1.v_v2; + +SHOW CREATE VIEW v_mysqluser1_t1; +SHOW CREATE VIEW v_mysqluser1_t2; +SHOW CREATE VIEW v_mysqluser1_f1; +SHOW CREATE VIEW v_mysqluser1_v1; +SHOW CREATE VIEW v_mysqluser1_v2; + +--connection default +--echo # Testing the case when the views reference missing objects. +--echo # Obviously, there are no privileges to check for, so we +--echo # need only each object type once. +DROP TABLE t1; +DROP FUNCTION f1; +DROP VIEW v1; + +--connection connection1 +SHOW CREATE VIEW mysqltest1.v_t1; +SHOW CREATE VIEW mysqltest1.v_f1; +SHOW CREATE VIEW mysqltest1.v_v1; + +SHOW CREATE VIEW v_mysqluser1_t1; +SHOW CREATE VIEW v_mysqluser1_f1; +SHOW CREATE VIEW v_mysqluser1_v1; + +--connection default +REVOKE SHOW VIEW ON v_t1 FROM mysqluser1@localhost; +REVOKE SHOW VIEW ON v_f1 FROM mysqluser1@localhost; +REVOKE SHOW VIEW ON v_v1 FROM mysqluser1@localhost; + +--connection connection1 +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest1.v_t1; +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest1.v_f1; +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest1.v_v1; +SHOW CREATE VIEW v_mysqluser1_t1; +SHOW CREATE VIEW v_mysqluser1_f1; +SHOW CREATE VIEW v_mysqluser1_v1; + +--disconnect connection1 +--connection default +DROP USER mysqluser1@localhost; +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; +USE test; + +CREATE TABLE t1( a INT ); +CREATE DEFINER = no_such_user@no_such_host VIEW v1 AS SELECT * FROM t1; +SHOW CREATE VIEW v1; +DROP TABLE t1; +DROP VIEW v1; + # Wait till we reached the initial number of concurrent sessions --source include/wait_until_count_sessions.inc +--echo # +--echo # Bug #46019: ERROR 1356 When selecting from within another +--echo # view that has Group By +--echo # +CREATE DATABASE mysqltest1; +USE mysqltest1; + +CREATE TABLE t1 (a INT); + +CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT a FROM t1 GROUP BY a; +CREATE SQL SECURITY INVOKER VIEW v2 AS SELECT a FROM v1; + +CREATE USER mysqluser1; + +GRANT SELECT ON TABLE t1 TO mysqluser1; +GRANT SELECT, SHOW VIEW ON TABLE v1 TO mysqluser1; +GRANT SELECT, SHOW VIEW ON TABLE v2 TO mysqluser1; + +--connect (mysqluser1, localhost, mysqluser1,,mysqltest1) +SELECT a FROM v1; +SELECT a FROM v2; + +--connection default +--disconnect mysqluser1 +DROP USER mysqluser1; +DROP DATABASE mysqltest1; diff --git a/mysql-test/t/warnings.test b/mysql-test/t/warnings.test index b8235825cf2..3c9129aedb1 100644 --- a/mysql-test/t/warnings.test +++ b/mysql-test/t/warnings.test @@ -227,4 +227,11 @@ insert into t2 values(@q); drop table t1, t2; +# +# Bug#42364 SHOW ERRORS returns empty resultset after dropping non existent table +# +--error ER_BAD_TABLE_ERROR +DROP TABLE t1; +SHOW ERRORS; + --echo End of 5.0 tests diff --git a/mysql-test/t/windows.test b/mysql-test/t/windows.test index 89cd2ed19e8..b7d31948d23 100755 --- a/mysql-test/t/windows.test +++ b/mysql-test/t/windows.test @@ -92,3 +92,9 @@ execute abc; execute abc; deallocate prepare abc; +--echo # +--echo # Bug#45498: Socket variable not available on Windows +--echo # + +SELECT VARIABLE_NAME FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES + WHERE VARIABLE_NAME = 'socket'; diff --git a/mysql-test/t/xa.test b/mysql-test/t/xa.test index 7b1c6a268d5..f84d822170f 100644 --- a/mysql-test/t/xa.test +++ b/mysql-test/t/xa.test @@ -149,6 +149,68 @@ xa end 'a'; xa prepare 'a'; xa commit 'a'; +# +# BUG#43171 - Assertion failed: thd->transaction.xid_state.xid.is_null() +# +CREATE TABLE t1(a INT, KEY(a)) ENGINE=InnoDB; +INSERT INTO t1 VALUES(1),(2); +connect(con1,localhost,root,,); + +# Part 1: Prepare to test XA START after regular transaction deadlock +BEGIN; +UPDATE t1 SET a=3 WHERE a=1; + +connection default; +BEGIN; +UPDATE t1 SET a=4 WHERE a=2; + +connection con1; +let $conn_id= `SELECT CONNECTION_ID()`; +SEND UPDATE t1 SET a=5 WHERE a=2; + +connection default; +let $wait_timeout= 2; +let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE ID=$conn_id AND STATE='Searching rows for update'; +--source include/wait_condition.inc + +--error ER_LOCK_DEADLOCK +UPDATE t1 SET a=5 WHERE a=1; +ROLLBACK; + +# Part 2: Prepare to test XA START after XA transaction deadlock +connection con1; +REAP; +ROLLBACK; +BEGIN; +UPDATE t1 SET a=3 WHERE a=1; + +connection default; +XA START 'xid1'; +UPDATE t1 SET a=4 WHERE a=2; + +connection con1; +SEND UPDATE t1 SET a=5 WHERE a=2; + +connection default; +let $wait_timeout= 2; +let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE ID=$conn_id AND STATE='Searching rows for update'; +--source include/wait_condition.inc + +--error ER_LOCK_DEADLOCK +UPDATE t1 SET a=5 WHERE a=1; +--error ER_XA_RBDEADLOCK +XA END 'xid1'; +XA ROLLBACK 'xid1'; + +XA START 'xid1'; +XA END 'xid1'; +XA ROLLBACK 'xid1'; + +disconnect con1; +DROP TABLE t1; + # Wait till all disconnects are completed --source include/wait_until_count_sessions.inc diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 5b06273ad6b..6ea2817e240 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -1,4 +1,3 @@ -# # Suppress some common (not fatal) errors in system libraries found by valgrind # @@ -894,3 +893,101 @@ obj: /lib64/libnss_dns-*so) fun: gethostbyaddr_r } + +# suppressions for glibc 2.6.1 64 bit + +{ + Mem loss within nptl_pthread_exit_hack_handler 6 + Memcheck:Leak + fun:malloc + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/libc-*.so + obj:*/ld-*.so + obj:*/libc-*.so + fun:__libc_dlopen_mode + fun:pthread_cancel_init + fun:_Unwind_ForcedUnwind + fun:__pthread_unwind + fun:pthread_exit + fun:nptl_pthread_exit_hack_handler +} + +{ + Mem loss within nptl_pthread_exit_hack_handler 7 + Memcheck:Leak + fun:malloc + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/libc-*.so + obj:*/ld-*.so + obj:*/libc-*.so + fun:__libc_dlopen_mode + fun:pthread_cancel_init + fun:_Unwind_ForcedUnwind + fun:__pthread_unwind + fun:pthread_exit + fun:nptl_pthread_exit_hack_handler + fun:start_thread + fun:clone +} + +{ + Mem loss within nptl_pthread_exit_hack_handler 8 + Memcheck:Leak + fun:calloc + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/libc-*.so + obj:*/ld-*.so + obj:*/libc-*.so + fun:__libc_dlopen_mode + fun:pthread_cancel_init + fun:_Unwind_ForcedUnwind + fun:__pthread_unwind + fun:pthread_exit + fun:nptl_pthread_exit_hack_handler + fun:start_thread + fun:clone +} + +{ + Mem loss within nptl_pthread_exit_hack_handler 8 + Memcheck:Leak + fun:calloc + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/ld-*.so + obj:*/libc-*.so + obj:*/ld-*.so + obj:*/libc-*.so + fun:__libc_dlopen_mode + fun:pthread_cancel_init + fun:_Unwind_ForcedUnwind + fun:__pthread_unwind + fun:pthread_exit + fun:nptl_pthread_exit_hack_handler +} + +# +# Pthread doesn't free all thread specific memory before program exists +# +{ + pthread allocate_tls memory loss in 2.6.1. + Memcheck:Leak + fun:calloc + obj:*/ld-*.so + fun:_dl_allocate_tls + fun:pthread_create* +} diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 8552eae3974..e9873fb0525 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -29,7 +29,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_ errors.c hash.c list.c md5.c mf_brkhant.c mf_cache.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_iocache.c mf_iocache2.c mf_keycache.c my_safehash.c mf_keycaches.c mf_loadpath.c mf_pack.c mf_path.c mf_qsort.c mf_qsort2.c - mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_strip.c mf_arr_appstr.c mf_tempdir.c + mf_radix.c mf_same.c mf_sort.c mf_soundex.c mf_arr_appstr.c mf_tempdir.c mf_tempfile.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_access.c my_aes.c my_alarm.c my_alloc.c my_append.c my_bit.c my_bitmap.c my_chmod.c my_chsize.c my_clock.c my_compress.c my_conio.c my_copy.c my_crc32.c my_create.c my_delete.c diff --git a/mysys/Makefile.am b/mysys/Makefile.am index f958d1821da..5137566c158 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2000-2006 MySQL AB +# Copyright (C) 2000-2006 MySQL AB, 2009 Sun Microsystems, Inc. # # 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 @@ -20,32 +20,32 @@ INCLUDES = @ZLIB_INCLUDES@ -I$(top_builddir)/include \ -I$(top_srcdir)/include -I$(srcdir) pkglib_LIBRARIES = libmysys.a LDADD = libmysys.a $(top_builddir)/strings/libmystrings.a $(top_builddir)/dbug/libdbug.a -noinst_HEADERS = mysys_priv.h my_static.h my_handler_errors.h my_safehash.h +noinst_HEADERS = mysys_priv.h my_static.h my_handler_errors.h \ + my_safehash.h libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ mf_path.c mf_loadpath.c my_file.c \ my_open.c my_create.c my_dup.c my_seek.c my_read.c \ my_pread.c my_write.c my_getpagesize.c \ - my_safehash.c \ - mf_keycache.c mf_keycaches.c my_crc32.c \ + my_crc32.c \ mf_iocache.c mf_iocache2.c mf_cache.c mf_tempfile.c \ mf_tempdir.c my_lock.c mf_brkhant.c my_alarm.c \ my_malloc.c my_realloc.c my_once.c mulalloc.c \ my_alloc.c safemalloc.c my_new.cc \ - my_vle.c my_atomic.c lf_hash.c \ - lf_dynarray.c lf_alloc-pin.c \ + my_vle.c my_atomic.c \ + my_safehash.c lf_hash.c lf_dynarray.c lf_alloc-pin.c \ + my_rnd.c my_uuid.c my_chmod.c \ my_fopen.c my_fstream.c my_getsystime.c \ - my_rnd.c my_uuid.c \ my_error.c errors.c my_div.c my_messnc.c \ mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \ my_symlink.c my_symlink2.c \ - mf_pack.c mf_unixpath.c mf_strip.c mf_arr_appstr.c \ + mf_pack.c mf_unixpath.c mf_arr_appstr.c \ mf_wcomp.c mf_wfile.c my_gethwaddr.c \ mf_qsort.c mf_qsort2.c mf_sort.c \ ptr_cmp.c mf_radix.c queues.c my_getncpus.c \ tree.c trie.c list.c hash.c array.c string.c typelib.c \ my_copy.c my_append.c my_lib.c \ my_delete.c my_rename.c my_redel.c \ - my_chsize.c my_chmod.c my_clock.c \ + my_chsize.c my_clock.c \ my_quick.c my_lockmem.c my_static.c \ my_sync.c my_getopt.c my_mkdir.c \ default_modify.c default.c \ @@ -57,12 +57,19 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ my_memmem.c stacktrace.c \ my_windac.c my_access.c base64.c my_libwrap.c \ wqueue.c -if THREAD -libmysys_a_SOURCES+= thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \ - thr_mutex.c thr_rwlock.c waiting_threads.c + +if NEED_THREAD +# mf_keycache is used only in the server, so it is safe to leave the file +# out of the non-threaded library. +# In fact, it will currently not compile without thread support. +libmysys_a_SOURCES += mf_keycache.c mf_keycaches.c endif -EXTRA_DIST = CMakeLists.txt mf_soundex.c \ + +EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \ + thr_mutex.c thr_rwlock.c waiting_threads.c \ + CMakeLists.txt mf_soundex.c \ my_conio.c my_wincond.c my_winthread.c +libmysys_a_LIBADD = @THREAD_LOBJECTS@ # test_dir_DEPENDENCIES= $(LIBRARIES) # testhash_DEPENDENCIES= $(LIBRARIES) # test_charset_DEPENDENCIES= $(LIBRARIES) @@ -76,6 +83,8 @@ DEFS = -DDEFAULT_BASEDIR=\"$(prefix)\" \ -DDEFAULT_SYSCONFDIR="\"$(sysconfdir)\"" \ @DEFS@ +libmysys_a_DEPENDENCIES= @THREAD_LOBJECTS@ + # I hope this always does the right thing. Otherwise this is only test programs FLAGS=$(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) @NOINST_LDFLAGS@ diff --git a/mysys/hash.c b/mysys/hash.c index 136c2854bbe..0e22ddcf215 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -338,13 +338,8 @@ my_bool my_hash_insert(HASH *info, const uchar *record) { int flag; size_t idx,halfbuff,hash_nr,first_index; - uchar *ptr_to_rec,*ptr_to_rec2; - HASH_LINK *data,*empty,*gpos,*gpos2,*pos; - - LINT_INIT(gpos); - LINT_INIT(gpos2); - LINT_INIT(ptr_to_rec); - LINT_INIT(ptr_to_rec2); + uchar *UNINIT_VAR(ptr_to_rec),*UNINIT_VAR(ptr_to_rec2); + HASH_LINK *data,*empty,*UNINIT_VAR(gpos),*UNINIT_VAR(gpos2),*pos; if (info->flags & HASH_UNIQUE) { diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index ece6c35888d..0630d194234 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -13,7 +13,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/** + @file These functions handle keyblock cacheing for ISAM and MyISAM tables. One cache can handle many files. @@ -36,7 +37,9 @@ blocks_unused is the sum of never used blocks in the pool and of currently free blocks. blocks_used is the number of blocks fetched from the pool and as such gives the maximum number of in-use blocks at any time. +*/ +/* Key Cache Locking ================= @@ -368,8 +371,8 @@ static inline uint next_power(uint value) */ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, - size_t use_mem, uint division_limit, - uint age_threshold) + size_t use_mem, uint division_limit, + uint age_threshold) { ulong blocks, hash_links; size_t length; @@ -560,8 +563,8 @@ err: */ int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, - size_t use_mem, uint division_limit, - uint age_threshold) + size_t use_mem, uint division_limit, + uint age_threshold) { int blocks; DBUG_ENTER("resize_key_cache"); @@ -760,6 +763,13 @@ void end_key_cache(KEY_CACHE *keycache, my_bool cleanup) (ulong) keycache->global_cache_r_requests, (ulong) keycache->global_cache_read)); + /* + Reset these values to be able to detect a disabled key cache. + See Bug#44068 (RESTORE can disable the MyISAM Key Cache). + */ + keycache->blocks_used= 0; + keycache->blocks_unused= 0; + if (cleanup) { pthread_mutex_destroy(&keycache->cache_lock); @@ -1343,7 +1353,11 @@ static void unreg_request(KEY_CACHE *keycache, DBUG_ASSERT(block->prev_changed && *block->prev_changed == block); DBUG_ASSERT(!block->next_used); DBUG_ASSERT(!block->prev_used); - if (! --block->requests) + /* + Unregister the request, but do not link erroneous blocks into the + LRU ring. + */ + if (!--block->requests && !(block->status & BLOCK_ERROR)) { my_bool hot; if (block->hits_left) @@ -1425,8 +1439,7 @@ static void wait_for_readers(KEY_CACHE *keycache, #ifdef THREAD struct st_my_thread_var *thread= my_thread_var; DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE)); - DBUG_ASSERT(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH | - BLOCK_CHANGED))); + DBUG_ASSERT(!(block->status & (BLOCK_IN_FLUSH | BLOCK_CHANGED))); DBUG_ASSERT(block->hash_link); DBUG_ASSERT(block->hash_link->block == block); /* Linked in file_blocks or changed_blocks hash. */ @@ -1716,6 +1729,7 @@ restart: - block assigned but not yet read from file (invalid data). */ +#ifdef THREAD if (keycache->in_resize) { /* This is a request during a resize operation */ @@ -1957,6 +1971,9 @@ restart: } DBUG_RETURN(0); } +#else /* THREAD */ + DBUG_ASSERT(!keycache->in_resize); +#endif if (page_status == PAGE_READ && (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH | @@ -2210,9 +2227,9 @@ restart: thread might change the block->hash_link value */ error= my_pwrite(block->hash_link->file, - block->buffer+block->offset, + block->buffer + block->offset, block->length - block->offset, - block->hash_link->diskpos+ block->offset, + block->hash_link->diskpos + block->offset, MYF(MY_NABP | MY_WAIT_IF_FULL)); keycache_pthread_mutex_lock(&keycache->cache_lock); @@ -2536,7 +2553,6 @@ uchar *key_cache_read(KEY_CACHE *keycache, reg1 BLOCK_LINK *block; uint read_length; uint offset; - uint status; int page_st; /* @@ -2571,9 +2587,11 @@ uchar *key_cache_read(KEY_CACHE *keycache, do { /* Cache could be disabled in a later iteration. */ - if (!keycache->can_be_used) - goto no_key_cache; + { + KEYCACHE_DBUG_PRINT("key_cache_read", ("keycache cannot be used")); + goto no_key_cache; + } /* Start reading at the beginning of the cache block. */ filepos-= offset; /* Do not read beyond the end of the cache block. */ @@ -2634,7 +2652,7 @@ uchar *key_cache_read(KEY_CACHE *keycache, } /* block status may have added BLOCK_ERROR in the above 'if'. */ - if (!((status= block->status) & BLOCK_ERROR)) + if (!(block->status & BLOCK_ERROR)) { #ifndef THREAD if (! return_buffer) @@ -2660,14 +2678,22 @@ uchar *key_cache_read(KEY_CACHE *keycache, remove_reader(block); - /* - Link the block into the LRU ring if it's the last submitted - request for the block. This enables eviction for the block. - */ - unreg_request(keycache, block, 1); + /* Error injection for coverage testing. */ + DBUG_EXECUTE_IF("key_cache_read_block_error", + block->status|= BLOCK_ERROR;); - if (status & BLOCK_ERROR) + /* Do not link erroneous blocks into the LRU ring, but free them. */ + if (!(block->status & BLOCK_ERROR)) + { + /* + Link the block into the LRU ring if it's the last submitted + request for the block. This enables eviction for the block. + */ + unreg_request(keycache, block, 1); + } + else { + free_block(keycache, block); error= 1; break; } @@ -2677,7 +2703,7 @@ uchar *key_cache_read(KEY_CACHE *keycache, if (return_buffer) DBUG_RETURN(block->buffer); #endif - next_block: + next_block: buff+= read_length; filepos+= read_length+offset; offset= 0; @@ -2685,6 +2711,7 @@ uchar *key_cache_read(KEY_CACHE *keycache, } while ((length-= read_length)); goto end; } + KEYCACHE_DBUG_PRINT("key_cache_read", ("keycache not initialized")); no_key_cache: /* Key cache is not used */ @@ -2705,6 +2732,7 @@ end: dec_counter_for_resize_op(keycache); keycache_pthread_mutex_unlock(&keycache->cache_lock); } + DBUG_PRINT("exit", ("error: %d", error )); DBUG_RETURN(error ? (uchar*) 0 : start); } @@ -2913,19 +2941,27 @@ int key_cache_insert(KEY_CACHE *keycache, DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE)); } /* end of if (!(block->status & BLOCK_ERROR)) */ - remove_reader(block); - /* - Link the block into the LRU ring if it's the last submitted - request for the block. This enables eviction for the block. - */ - unreg_request(keycache, block, 1); - - error= (block->status & BLOCK_ERROR); + /* Error injection for coverage testing. */ + DBUG_EXECUTE_IF("key_cache_insert_block_error", + block->status|= BLOCK_ERROR; errno=EIO;); - if (error) + /* Do not link erroneous blocks into the LRU ring, but free them. */ + if (!(block->status & BLOCK_ERROR)) + { + /* + Link the block into the LRU ring if it's the last submitted + request for the block. This enables eviction for the block. + */ + unreg_request(keycache, block, 1); + } + else + { + free_block(keycache, block); + error= 1; break; + } buff+= read_length; filepos+= read_length+offset; @@ -3206,14 +3242,24 @@ int key_cache_write(KEY_CACHE *keycache, */ remove_reader(block); - /* - Link the block into the LRU ring if it's the last submitted - request for the block. This enables eviction for the block. - */ - unreg_request(keycache, block, 1); + /* Error injection for coverage testing. */ + DBUG_EXECUTE_IF("key_cache_write_block_error", + block->status|= BLOCK_ERROR;); - if (block->status & BLOCK_ERROR) + /* Do not link erroneous blocks into the LRU ring, but free them. */ + if (!(block->status & BLOCK_ERROR)) + { + /* + Link the block into the LRU ring if it's the last submitted + request for the block. This enables eviction for the block. + */ + unreg_request(keycache, block, 1); + } + else { + /* Pretend a "clean" block to avoid complications. */ + block->status&= ~(BLOCK_CHANGED); + free_block(keycache, block); error= 1; break; } @@ -3288,8 +3334,9 @@ static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block) { KEYCACHE_THREAD_TRACE("free block"); KEYCACHE_DBUG_PRINT("free_block", - ("block %u to be freed, hash_link %p", - BLOCK_NUMBER(block), block->hash_link)); + ("block %u to be freed, hash_link %p status: %u", + BLOCK_NUMBER(block), block->hash_link, + block->status)); /* Assert that the block is not free already. And that it is in a clean state. Note that the block might just be assigned to a hash_link and @@ -3371,10 +3418,14 @@ static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block) if (block->status & BLOCK_IN_EVICTION) return; - /* Here the block must be in the LRU ring. Unlink it again. */ - DBUG_ASSERT(block->next_used && block->prev_used && - *block->prev_used == block); - unlink_block(keycache, block); + /* Error blocks are not put into the LRU ring. */ + if (!(block->status & BLOCK_ERROR)) + { + /* Here the block must be in the LRU ring. Unlink it again. */ + DBUG_ASSERT(block->next_used && block->prev_used && + *block->prev_used == block); + unlink_block(keycache, block); + } if (block->temperature == BLOCK_WARM) keycache->warm_blocks--; block->temperature= BLOCK_COLD; @@ -3463,8 +3514,7 @@ static int flush_cached_blocks(KEY_CACHE *keycache, (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE)); block->status|= BLOCK_IN_FLUSHWRITE; keycache_pthread_mutex_unlock(&keycache->cache_lock); - error= my_pwrite(file, - block->buffer+block->offset, + error= my_pwrite(file, block->buffer+block->offset, block->length - block->offset, block->hash_link->diskpos+ block->offset, MYF(MY_NABP | MY_WAIT_IF_FULL)); @@ -3491,7 +3541,6 @@ static int flush_cached_blocks(KEY_CACHE *keycache, right queue anyway. */ link_to_file_list(keycache, block, file, 1); - } block->status&= ~BLOCK_IN_FLUSH; /* @@ -3527,7 +3576,7 @@ static int flush_cached_blocks(KEY_CACHE *keycache, /* - flush all key blocks for a file to disk, but don't do any mutex locks. + Flush all key blocks for a file to disk, but don't do any mutex locks. SYNOPSIS flush_key_blocks_int() @@ -3693,7 +3742,6 @@ restart: { /* It's a temporary file */ DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED)); - /* free_block() must not be called with BLOCK_CHANGED. Note that we must not change the BLOCK_CHANGED flag outside of @@ -4404,8 +4452,8 @@ static void keycache_debug_print(const char * fmt,...) va_start(args,fmt); if (keycache_debug_log) { - VOID(vfprintf(keycache_debug_log, fmt, args)); - VOID(fputc('\n',keycache_debug_log)); + (void) vfprintf(keycache_debug_log, fmt, args); + (void) fputc('\n',keycache_debug_log); } va_end(args); } diff --git a/mysys/mf_strip.c b/mysys/mf_strip.c deleted file mode 100644 index b33620b1b2d..00000000000 --- a/mysys/mf_strip.c +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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 */ - -/* T|mmer en str{ng p{ slut_space */ - -#include "mysys_priv.h" - -/* - strip_sp(char * str) - Strips end-space from string and returns new length. -*/ - -size_t strip_sp(register char * str) -{ - reg2 char * found; - reg3 char * start; - - start=found=str; - - while (*str) - { - if (*str != ' ') - { - while (*++str && *str != ' ') {}; - if (!*str) - return (size_t) (str-start); /* Return stringlength */ - } - found=str; - while (*++str == ' ') {}; - } - *found= '\0'; /* Stripp at first space */ - return (size_t) (found-start); -} /* strip_sp */ diff --git a/mysys/my_copy.c b/mysys/my_copy.c index 62f60e9ce95..adc891358d4 100644 --- a/mysys/my_copy.c +++ b/mysys/my_copy.c @@ -89,6 +89,13 @@ int my_copy(const char *from, const char *to, myf MyFlags) goto err; } + /* sync the destination file */ + if (MyFlags & MY_SYNC) + { + if (my_sync(to_file, MyFlags)) + goto err; + } + if (my_close(from_file,MyFlags) | my_close(to_file,MyFlags)) DBUG_RETURN(-1); /* Error on close */ diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 3d961c3bcee..98d3b9756ed 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -1017,10 +1017,12 @@ static void init_one_value(const struct my_option *option, uchar* *variable, case GET_LL: *((longlong*) variable)= (longlong) getopt_ll_limit_value((longlong) value, option, NULL); break; - case GET_ULL: /* Fall through */ - case GET_SET: + case GET_ULL: *((ulonglong*) variable)= (ulonglong) getopt_ull_limit_value((ulonglong) value, option, NULL); break; + case GET_SET: + *((ulonglong*) variable)= (ulonglong) value; + break; case GET_DOUBLE: *((double*) variable)= (double) value; break; diff --git a/mysys/my_largepage.c b/mysys/my_largepage.c index a20111396cb..b50a606c8d8 100644 --- a/mysys/my_largepage.c +++ b/mysys/my_largepage.c @@ -121,7 +121,7 @@ uchar* my_large_malloc_int(size_t size, myf my_flags) DBUG_ENTER("my_large_malloc_int"); /* Align block size to my_large_page_size */ - size = ((size - 1) & ~(my_large_page_size - 1)) + my_large_page_size; + size= MY_ALIGN(size, (size_t) my_large_page_size); shmid = shmget(IPC_PRIVATE, size, SHM_HUGETLB | SHM_R | SHM_W); if (shmid < 0) diff --git a/mysys/my_static.c b/mysys/my_static.c index c33d05420c9..0ef5656b76f 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -104,6 +104,13 @@ static const char *proc_info_dummy(void *a __attribute__((unused)), /* this is to be able to call set_thd_proc_info from the C code */ const char *(*proc_info_hook)(void *, const char *, const char *, const char *, const unsigned int)= proc_info_dummy; +#if defined(ENABLED_DEBUG_SYNC) +/** + Global pointer to be set if callback function is defined + (e.g. in mysqld). See sql/debug_sync.cc. +*/ +void (*debug_sync_C_callback_ptr)(const char *, size_t); +#endif /* defined(ENABLED_DEBUG_SYNC) */ #ifdef __WIN__ /* from my_getsystime.c */ diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 716552bc31b..e105b48f386 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -134,10 +134,11 @@ my_bool my_thread_global_init(void) pthread_attr_t dummy_thread_attr; pthread_attr_init(&dummy_thread_attr); - pthread_attr_setdetachstate(&dummy_thread_attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setdetachstate(&dummy_thread_attr, PTHREAD_CREATE_JOINABLE); - pthread_create(&dummy_thread,&dummy_thread_attr, - nptl_pthread_exit_hack_handler, NULL); + if (pthread_create(&dummy_thread,&dummy_thread_attr, + nptl_pthread_exit_hack_handler, NULL) == 0) + (void)pthread_join(dummy_thread, NULL); } #endif /* TARGET_OS_LINUX */ diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c index 8b548a64079..b869b22bdea 100644 --- a/mysys/my_wincond.c +++ b/mysys/my_wincond.c @@ -121,7 +121,6 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, LeaveCriticalSection(&cond->lock_waiting); LeaveCriticalSection(mutex); - result= WaitForMultipleObjects(2, cond->events, FALSE, timeout); EnterCriticalSection(&cond->lock_waiting); diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 3eabde85a58..c830c4ed0cc 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -420,6 +420,28 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, my_bool can_deadlock= test(data->owner->info->n_cursors); DBUG_ENTER("wait_for_lock"); + /* + One can use this to signal when a thread is going to wait for a lock. + See debug_sync.cc. + + Beware of waiting for a signal here. The lock has aquired its mutex. + While waiting on a signal here, the locking thread could not aquire + the mutex to release the lock. One could lock up the table + completely. + + In detail it works so: When thr_lock() tries to acquire a table + lock, it locks the lock->mutex, checks if it can have the lock, and + if not, it calls wait_for_lock(). Here it unlocks the table lock + while waiting on a condition. The sync point is located before this + wait for condition. If we have a waiting action here, we hold the + the table locks mutex all the time. Any attempt to look at the table + lock by another thread blocks it immediately on lock->mutex. This + can easily become an unexpected and unobvious blockage. So be + warned: Do not request a WAIT_FOR action for the 'wait_for_lock' + sync point unless you really know what you do. + */ + DEBUG_SYNC_C("wait_for_lock"); + if (!in_wait_list) { (*wait->last)=data; /* Wait for lock */ diff --git a/mysys/typelib.c b/mysys/typelib.c index 26bfdaee2c2..247640ed222 100644 --- a/mysys/typelib.c +++ b/mysys/typelib.c @@ -190,7 +190,10 @@ my_ulonglong find_typeset(char *x, TYPELIB *lib, int *err) { (*err)++; i= x; - while (*x && *x != field_separator) x++; + while (*x && *x != field_separator) + x++; + if (x[0] && x[1]) // skip separator if found + x++; if ((find= find_type(i, lib, 2 | 8) - 1) < 0) DBUG_RETURN(0); result|= (ULL(1) << find); diff --git a/regex/CMakeLists.txt b/regex/CMakeLists.txt index a3088c00357..2e3b18c7bb0 100755 --- a/regex/CMakeLists.txt +++ b/regex/CMakeLists.txt @@ -18,7 +18,7 @@ SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -DSAFEMALLOC -DSAFE_MUT INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) -SET(REGEX_SOURCES debug.c regcomp.c regerror.c regexec.c regfree.c reginit.c split.c) +SET(REGEX_SOURCES regcomp.c regerror.c regexec.c regfree.c reginit.c) IF(NOT SOURCE_SUBLIBS) ADD_LIBRARY(regex ${REGEX_SOURCES}) diff --git a/scripts/make_win_bin_dist b/scripts/make_win_bin_dist index 0380d7f8c32..11f627b4276 100755 --- a/scripts/make_win_bin_dist +++ b/scripts/make_win_bin_dist @@ -350,6 +350,7 @@ fi mkdir $DESTDIR/mysql-test cp mysql-test/mysql-test-run.pl $DESTDIR/mysql-test/ +cp mysql-test/mysql-stress-test.pl $DESTDIR/mysql-test/ cp mysql-test/README $DESTDIR/mysql-test/ cp -R mysql-test/{t,r,include,suite,std_data,lib} $DESTDIR/mysql-test/ diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql index 67e18517915..923497b0ab2 100644 --- a/scripts/mysql_system_tables.sql +++ b/scripts/mysql_system_tables.sql @@ -62,7 +62,7 @@ CREATE TABLE IF NOT EXISTS time_zone_leap_second ( Transition_time bigint sign CREATE TABLE IF NOT EXISTS proc (db char(64) collate utf8_bin DEFAULT '' NOT NULL, name char(64) DEFAULT '' NOT NULL, type enum('FUNCTION','PROCEDURE') NOT NULL, specific_name char(64) DEFAULT '' NOT NULL, language enum('SQL') DEFAULT 'SQL' NOT NULL, sql_data_access enum( 'CONTAINS_SQL', 'NO_SQL', 'READS_SQL_DATA', 'MODIFIES_SQL_DATA') DEFAULT 'CONTAINS_SQL' NOT NULL, is_deterministic enum('YES','NO') DEFAULT 'NO' NOT NULL, security_type enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL, param_list blob NOT NULL, returns longblob DEFAULT '' NOT NULL, body longblob NOT NULL, definer char(77) collate utf8_bin DEFAULT '' NOT NULL, created timestamp, modified timestamp, sql_mode set( 'REAL_AS_FLOAT', 'PIPES_AS_CONCAT', 'ANSI_QUOTES', 'IGNORE_SPACE', 'NOT_USED', 'ONLY_FULL_GROUP_BY', 'NO_UNSIGNED_SUBTRACTION', 'NO_DIR_IN_CREATE', 'POSTGRESQL', 'ORACLE', 'MSSQL', 'DB2', 'MAXDB', 'NO_KEY_OPTIONS', 'NO_TABLE_OPTIONS', 'NO_FIELD_OPTIONS', 'MYSQL323', 'MYSQL40', 'ANSI', 'NO_AUTO_VALUE_ON_ZERO', 'NO_BACKSLASH_ESCAPES', 'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', 'NO_ZERO_IN_DATE', 'NO_ZERO_DATE', 'INVALID_DATES', 'ERROR_FOR_DIVISION_BY_ZERO', 'TRADITIONAL', 'NO_AUTO_CREATE_USER', 'HIGH_NOT_PRECEDENCE', 'NO_ENGINE_SUBSTITUTION', 'PAD_CHAR_TO_FULL_LENGTH') DEFAULT '' NOT NULL, comment char(64) collate utf8_bin DEFAULT '' NOT NULL, character_set_client char(32) collate utf8_bin, collation_connection char(32) collate utf8_bin, db_collation char(32) collate utf8_bin, body_utf8 longblob, PRIMARY KEY (db,name,type)) engine=MyISAM character set utf8 comment='Stored Procedures'; -CREATE TABLE IF NOT EXISTS procs_priv ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Routine_name char(64) binary DEFAULT '' NOT NULL, Routine_type enum('FUNCTION','PROCEDURE') NOT NULL, Grantor char(77) DEFAULT '' NOT NULL, Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Timestamp timestamp(14), PRIMARY KEY (Host,Db,User,Routine_name,Routine_type), KEY Grantor (Grantor) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges'; +CREATE TABLE IF NOT EXISTS procs_priv ( Host char(60) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL, Routine_name char(64) COLLATE utf8_general_ci DEFAULT '' NOT NULL, Routine_type enum('FUNCTION','PROCEDURE') NOT NULL, Grantor char(77) DEFAULT '' NOT NULL, Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Timestamp timestamp(14), PRIMARY KEY (Host,Db,User,Routine_name,Routine_type), KEY Grantor (Grantor) ) engine=MyISAM CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges'; -- Create general_log if CSV is enabled. diff --git a/scripts/mysql_system_tables_fix.sql b/scripts/mysql_system_tables_fix.sql index a6497f57f0a..1844860c84d 100644 --- a/scripts/mysql_system_tables_fix.sql +++ b/scripts/mysql_system_tables_fix.sql @@ -337,6 +337,10 @@ ALTER TABLE procs_priv MODIFY Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL; +ALTER IGNORE TABLE procs_priv + MODIFY Routine_name char(64) + COLLATE utf8_general_ci DEFAULT '' NOT NULL; + ALTER TABLE procs_priv ADD Routine_type enum('FUNCTION','PROCEDURE') COLLATE utf8_general_ci NOT NULL AFTER Routine_name; diff --git a/sql-common/client.c b/sql-common/client.c index c290525a1c0..9a8444a84e9 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -389,7 +389,7 @@ HANDLE create_named_pipe(MYSQL *mysql, uint connect_timeout, char **arg_host, 0, NULL, OPEN_EXISTING, - 0, + FILE_FLAG_OVERLAPPED, NULL )) != INVALID_HANDLE_VALUE) break; if (GetLastError() != ERROR_PIPE_BUSY) @@ -623,7 +623,7 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout) err2: if (error_allow == 0) { - net->vio= vio_new_win32shared_memory(net,handle_file_map,handle_map, + net->vio= vio_new_win32shared_memory(handle_file_map,handle_map, event_server_wrote, event_server_read,event_client_wrote, event_client_read,event_conn_closed); @@ -2033,7 +2033,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, } else { - net->vio=vio_new_win32pipe(hPipe); + net->vio= vio_new_win32pipe(hPipe); my_snprintf(host_info=buff, sizeof(buff)-1, ER(CR_NAMEDPIPE_CONNECTION), unix_socket); } diff --git a/sql-common/my_time.c b/sql-common/my_time.c index 2ec1fc253a7..95078a50097 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -165,7 +165,7 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, uint add_hours= 0, start_loop; ulong not_zero_date, allow_space; my_bool is_internal_format; - const char *pos, *last_field_pos; + const char *pos, *UNINIT_VAR(last_field_pos); const char *end=str+length; const uchar *format_position; my_bool found_delimitier= 0, found_space= 0; @@ -174,7 +174,6 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, DBUG_PRINT("ENTER",("str: %.*s",length,str)); LINT_INIT(field_length); - LINT_INIT(last_field_pos); *was_cut= 0; diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 58ba26782f9..e50da7b88d3 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -65,6 +65,7 @@ SET (SQL_SOURCE sql_error.cc sql_handler.cc sql_help.cc sql_insert.cc sql_lex.cc sql_list.cc sql_load.cc sql_manager.cc sql_map.cc sql_parse.cc sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc + debug_sync.cc debug_sync.h sql_repl.cc sql_select.cc sql_show.cc sql_state.c sql_string.cc sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc diff --git a/sql/Makefile.am b/sql/Makefile.am index 00342f7034e..af34e961480 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -59,6 +59,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ ha_ndbcluster.h ha_ndbcluster_cond.h \ ha_ndbcluster_binlog.h ha_ndbcluster_tables.h \ ha_partition.h rpl_constants.h \ + debug_sync.h \ opt_range.h protocol.h rpl_tblmap.h rpl_utility.h \ rpl_reporting.h \ log.h log_slow.h sql_show.h rpl_rli.h rpl_mi.h \ @@ -103,6 +104,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \ discover.cc time.cc opt_range.cc opt_sum.cc \ records.cc filesort.cc handler.cc \ ha_partition.cc \ + debug_sync.cc \ sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \ sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \ diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc new file mode 100644 index 00000000000..2580d526b52 --- /dev/null +++ b/sql/debug_sync.cc @@ -0,0 +1,1906 @@ +/* Copyright (C) 2008 MySQL AB, 2008 - 2009 Sun Microsystems, Inc. + + 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 */ + +/** + == Debug Sync Facility == + + The Debug Sync Facility allows placement of synchronization points in + the server code by using the DEBUG_SYNC macro: + + open_tables(...) + + DEBUG_SYNC(thd, "after_open_tables"); + + lock_tables(...) + + When activated, a sync point can + + - Emit a signal and/or + - Wait for a signal + + Nomenclature: + + - signal: A value of a global variable that persists + until overwritten by a new signal. The global + variable can also be seen as a "signal post" + or "flag mast". Then the signal is what is + attached to the "signal post" or "flag mast". + + - emit a signal: Assign the value (the signal) to the global + variable ("set a flag") and broadcast a + global condition to wake those waiting for + a signal. + + - wait for a signal: Loop over waiting for the global condition until + the global value matches the wait-for signal. + + By default, all sync points are inactive. They do nothing (except to + burn a couple of CPU cycles for checking if they are active). + + A sync point becomes active when an action is requested for it. + To do so, put a line like this in the test case file: + + SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed'; + + This activates the sync point 'after_open_tables'. It requests it to + emit the signal 'opened' and wait for another thread to emit the signal + 'flushed' when the thread's execution runs through the sync point. + + For every sync point there can be one action per thread only. Every + thread can request multiple actions, but only one per sync point. In + other words, a thread can activate multiple sync points. + + Here is an example how to activate and use the sync points: + + --connection conn1 + SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed'; + send INSERT INTO t1 VALUES(1); + --connection conn2 + SET DEBUG_SYNC= 'now WAIT_FOR opened'; + SET DEBUG_SYNC= 'after_abort_locks SIGNAL flushed'; + FLUSH TABLE t1; + + When conn1 runs through the INSERT statement, it hits the sync point + 'after_open_tables'. It notices that it is active and executes its + action. It emits the signal 'opened' and waits for another thread to + emit the signal 'flushed'. + + conn2 waits immediately at the special sync point 'now' for another + thread to emit the 'opened' signal. + + A signal remains in effect until it is overwritten. If conn1 signals + 'opened' before conn2 reaches 'now', conn2 will still find the 'opened' + signal. It does not wait in this case. + + When conn2 reaches 'after_abort_locks', it signals 'flushed', which lets + conn1 awake. + + Normally the activation of a sync point is cleared when it has been + executed. Sometimes it is necessary to keep the sync point active for + another execution. You can add an execute count to the action: + + SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 3'; + + This sets the signal point's activation counter to 3. Each execution + decrements the counter. After the third execution the sync point + becomes inactive. + + One of the primary goals of this facility is to eliminate sleeps from + the test suite. In most cases it should be possible to rewrite test + cases so that they do not need to sleep. (But this facility cannot + synchronize multiple processes.) However, to support test development, + and as a last resort, sync point waiting times out. There is a default + timeout, but it can be overridden: + + SET DEBUG_SYNC= 'name WAIT_FOR sig TIMEOUT 10 EXECUTE 2'; + + TIMEOUT 0 is special: If the signal is not present, the wait times out + immediately. + + When a wait timed out (even on TIMEOUT 0), a warning is generated so + that it shows up in the test result. + + You can throw an error message and kill the query when a synchronization + point is hit a certain number of times: + + SET DEBUG_SYNC= 'name HIT_LIMIT 3'; + + Or combine it with signal and/or wait: + + SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 2 HIT_LIMIT 3'; + + Here the first two hits emit the signal, the third hit returns the error + message and kills the query. + + For cases where you are not sure that an action is taken and thus + cleared in any case, you can force to clear (deactivate) a sync point: + + SET DEBUG_SYNC= 'name CLEAR'; + + If you want to clear all actions and clear the global signal, use: + + SET DEBUG_SYNC= 'RESET'; + + This is the only way to reset the global signal to an empty string. + + For testing of the facility itself you can execute a sync point just + as if it had been hit: + + SET DEBUG_SYNC= 'name TEST'; + + + === Formal Syntax === + + The string to "assign" to the DEBUG_SYNC variable can contain: + + {RESET | + <sync point name> TEST | + <sync point name> CLEAR | + <sync point name> {{SIGNAL <signal name> | + WAIT_FOR <signal name> [TIMEOUT <seconds>]} + [EXECUTE <count>] &| HIT_LIMIT <count>} + + Here '&|' means 'and/or'. This means that one of the sections + separated by '&|' must be present or both of them. + + + === Activation/Deactivation === + + The facility is an optional part of the MySQL server. + It is enabled in a debug server by default. + + ./configure --enable-debug-sync + + The Debug Sync Facility, when compiled in, is disabled by default. It + can be enabled by a mysqld command line option: + + --debug-sync-timeout[=default_wait_timeout_value_in_seconds] + + 'default_wait_timeout_value_in_seconds' is the default timeout for the + WAIT_FOR action. If set to zero, the facility stays disabled. + + The facility is enabled by default in the test suite, but can be + disabled with: + + mysql-test-run.pl ... --debug-sync-timeout=0 ... + + Likewise the default wait timeout can be set: + + mysql-test-run.pl ... --debug-sync-timeout=10 ... + + The command line option influences the readable value of the system + variable 'debug_sync'. + + * If the facility is not compiled in, the system variable does not exist. + + * If --debug-sync-timeout=0 the value of the variable reads as "OFF". + + * Otherwise the value reads as "ON - current signal: " followed by the + current signal string, which can be empty. + + The readable variable value is the same, regardless if read as global + or session value. + + Setting the 'debug-sync' system variable requires 'SUPER' privilege. + You can never read back the string that you assigned to the variable, + unless you assign the value that the variable does already have. But + that would give a parse error. A syntactically correct string is + parsed into a debug sync action and stored apart from the variable value. + + + === Implementation === + + Pseudo code for a sync point: + + #define DEBUG_SYNC(thd, sync_point_name) + if (unlikely(opt_debug_sync_timeout)) + debug_sync(thd, STRING_WITH_LEN(sync_point_name)) + + The sync point performs a binary search in a sorted array of actions + for this thread. + + The SET DEBUG_SYNC statement adds a requested action to the array or + overwrites an existing action for the same sync point. When it adds a + new action, the array is sorted again. + + + === A typical synchronization pattern === + + There are quite a few places in MySQL, where we use a synchronization + pattern like this: + + pthread_mutex_lock(&mutex); + thd->enter_cond(&condition_variable, &mutex, new_message); + #if defined(ENABLE_DEBUG_SYNC) + if (!thd->killed && !end_of_wait_condition) + DEBUG_SYNC(thd, "sync_point_name"); + #endif + while (!thd->killed && !end_of_wait_condition) + pthread_cond_wait(&condition_variable, &mutex); + thd->exit_cond(old_message); + + Here some explanations: + + thd->enter_cond() is used to register the condition variable and the + mutex in thd->mysys_var. This is done to allow the thread to be + interrupted (killed) from its sleep. Another thread can find the + condition variable to signal and mutex to use for synchronization in + this thread's THD::mysys_var. + + thd->enter_cond() requires the mutex to be acquired in advance. + + thd->exit_cond() unregisters the condition variable and mutex and + releases the mutex. + + If you want to have a Debug Sync point with the wait, please place it + behind enter_cond(). Only then you can safely decide, if the wait will + be taken. Also you will have THD::proc_info correct when the sync + point emits a signal. DEBUG_SYNC sets its own proc_info, but restores + the previous one before releasing its internal mutex. As soon as + another thread sees the signal, it does also see the proc_info from + before entering the sync point. In this case it will be "new_message", + which is associated with the wait that is to be synchronized. + + In the example above, the wait condition is repeated before the sync + point. This is done to skip the sync point, if no wait takes place. + The sync point is before the loop (not inside the loop) to have it hit + once only. It is possible that the condition variable is signaled + multiple times without the wait condition to be true. + + A bit off-topic: At some places, the loop is taken around the whole + synchronization pattern: + + while (!thd->killed && !end_of_wait_condition) + { + pthread_mutex_lock(&mutex); + thd->enter_cond(&condition_variable, &mutex, new_message); + if (!thd->killed [&& !end_of_wait_condition]) + { + [DEBUG_SYNC(thd, "sync_point_name");] + pthread_cond_wait(&condition_variable, &mutex); + } + thd->exit_cond(old_message); + } + + Note that it is important to repeat the test for thd->killed after + enter_cond(). Otherwise the killing thread may kill this thread after + it tested thd->killed in the loop condition and before it registered + the condition variable and mutex in enter_cond(). In this case, the + killing thread does not know that this thread is going to wait on a + condition variable. It would just set THD::killed. But if we would not + test it again, we would go asleep though we are killed. If the killing + thread would kill us when we are after the second test, but still + before sleeping, we hold the mutex, which is registered in mysys_var. + The killing thread would try to acquire the mutex before signaling + the condition variable. Since the mutex is only released implicitly in + pthread_cond_wait(), the signaling happens at the right place. We + have a safe synchronization. + + === Co-work with the DBUG facility === + + When running the MySQL test suite with the --debug command line + option, the Debug Sync Facility writes trace messages to the DBUG + trace. The following shell commands proved very useful in extracting + relevant information: + + egrep 'query:|debug_sync_exec:' mysql-test/var/log/mysqld.1.trace + + It shows all executed SQL statements and all actions executed by + synchronization points. + + Sometimes it is also useful to see, which synchronization points have + been run through (hit) with or without executing actions. Then add + "|debug_sync_point:" to the egrep pattern. + + === Further reading === + + For a discussion of other methods to synchronize threads see + http://forge.mysql.com/wiki/MySQL_Internals_Test_Synchronization + + For complete syntax tests, functional tests, and examples see the test + case debug_sync.test. + + See also worklog entry WL#4259 - Test Synchronization Facility +*/ + +#include "debug_sync.h" + +#if defined(ENABLED_DEBUG_SYNC) + +/* + Due to weaknesses in our include files, we need to include + mysql_priv.h here. To have THD declared, we need to include + sql_class.h. This includes log_event.h, which in turn requires + declarations from mysql_priv.h (e.g. OPTION_AUTO_IS_NULL). + mysql_priv.h includes almost everything, so is sufficient here. +*/ +#include "mysql_priv.h" + +/* + Action to perform at a synchronization point. + NOTE: This structure is moved around in memory by realloc(), qsort(), + and memmove(). Do not add objects with non-trivial constuctors + or destructors, which might prevent moving of this structure + with these functions. +*/ +struct st_debug_sync_action +{ + ulong activation_count; /* max(hit_limit, execute) */ + ulong hit_limit; /* hits before kill query */ + ulong execute; /* executes before self-clear */ + ulong timeout; /* wait_for timeout */ + String signal; /* signal to emit */ + String wait_for; /* signal to wait for */ + String sync_point; /* sync point name */ + bool need_sort; /* if new action, array needs sort */ +}; + +/* Debug sync control. Referenced by THD. */ +struct st_debug_sync_control +{ + st_debug_sync_action *ds_action; /* array of actions */ + uint ds_active; /* # active actions */ + uint ds_allocated; /* # allocated actions */ + ulonglong dsp_hits; /* statistics */ + ulonglong dsp_executed; /* statistics */ + ulonglong dsp_max_active; /* statistics */ + /* + thd->proc_info points at unsynchronized memory. + It must not go away as long as the thread exists. + */ + char ds_proc_info[80]; /* proc_info string */ +}; + + +/** + Definitions for the debug sync facility. + 1. Global string variable to hold a "signal" ("signal post", "flag mast"). + 2. Global condition variable for signaling and waiting. + 3. Global mutex to synchronize access to the above. +*/ +struct st_debug_sync_globals +{ + String ds_signal; /* signal variable */ + pthread_cond_t ds_cond; /* condition variable */ + pthread_mutex_t ds_mutex; /* mutex variable */ + ulonglong dsp_hits; /* statistics */ + ulonglong dsp_executed; /* statistics */ + ulonglong dsp_max_active; /* statistics */ +}; +static st_debug_sync_globals debug_sync_global; /* All globals in one object */ + +/** + Callback pointer for C files. +*/ +extern "C" void (*debug_sync_C_callback_ptr)(const char *, size_t); + + +/** + Callback for debug sync, to be used by C files. See thr_lock.c for example. + + @description + + We cannot place a sync point directly in C files (like those in mysys or + certain storage engines written mostly in C like MyISAM or Maria). Because + they are C code and do not include mysql_priv.h. So they do not know the + macro DEBUG_SYNC(thd, sync_point_name). The macro needs a 'thd' argument. + Hence it cannot be used in files outside of the sql/ directory. + + The workaround is to call back simple functions like this one from + non-sql/ files. + + We want to allow modules like thr_lock to be used without sql/ and + especially without Debug Sync. So we cannot just do a simple call + of the callback function. Instead we provide a global pointer in + the other file, which is to be set to the callback by Debug Sync. + If the pointer is not set, no call back will be done. If Debug + Sync sets the pointer to a callback function like this one, it will + be called. That way thr_lock.c does not have an undefined reference + to Debug Sync and can be used without it. Debug Sync, in contrast, + has an undefined reference to that pointer and thus requires + thr_lock to be linked too. But this is not a problem as it is part + of the MySQL server anyway. + + @note + The callback pointer in C files is set only if debug sync is + initialized. And this is done only if opt_debug_sync_timeout is set. +*/ + +static void debug_sync_C_callback(const char *sync_point_name, + size_t name_len) +{ + if (unlikely(opt_debug_sync_timeout)) + debug_sync(current_thd, sync_point_name, name_len); +} + + +/** + Initialize the debug sync facility at server start. + + @return status + @retval 0 ok + @retval != 0 error +*/ + +int debug_sync_init(void) +{ + DBUG_ENTER("debug_sync_init"); + + if (opt_debug_sync_timeout) + { + int rc; + + /* Initialize the global variables. */ + debug_sync_global.ds_signal.length(0); + if ((rc= pthread_cond_init(&debug_sync_global.ds_cond, NULL)) || + (rc= pthread_mutex_init(&debug_sync_global.ds_mutex, + MY_MUTEX_INIT_FAST))) + DBUG_RETURN(rc); /* purecov: inspected */ + + /* Set the call back pointer in C files. */ + debug_sync_C_callback_ptr= debug_sync_C_callback; + } + + DBUG_RETURN(0); +} + + +/** + End the debug sync facility. + + @description + This is called at server shutdown or after a thread initialization error. +*/ + +void debug_sync_end(void) +{ + DBUG_ENTER("debug_sync_end"); + + /* End the facility only if it had been initialized. */ + if (debug_sync_C_callback_ptr) + { + /* Clear the call back pointer in C files. */ + debug_sync_C_callback_ptr= NULL; + + /* Destroy the global variables. */ + debug_sync_global.ds_signal.free(); + (void) pthread_cond_destroy(&debug_sync_global.ds_cond); + (void) pthread_mutex_destroy(&debug_sync_global.ds_mutex); + + /* Print statistics. */ + { + char llbuff[22]; + sql_print_information("Debug sync points hit: %22s", + llstr(debug_sync_global.dsp_hits, llbuff)); + sql_print_information("Debug sync points executed: %22s", + llstr(debug_sync_global.dsp_executed, llbuff)); + sql_print_information("Debug sync points max active per thread: %22s", + llstr(debug_sync_global.dsp_max_active, llbuff)); + } + } + + DBUG_VOID_RETURN; +} + + +/* purecov: begin tested */ + +/** + Disable the facility after lack of memory if no error can be returned. + + @note + Do not end the facility here because the global variables can + be in use by other threads. +*/ + +static void debug_sync_emergency_disable(void) +{ + DBUG_ENTER("debug_sync_emergency_disable"); + + opt_debug_sync_timeout= 0; + + DBUG_PRINT("debug_sync", + ("Debug Sync Facility disabled due to lack of memory.")); + sql_print_error("Debug Sync Facility disabled due to lack of memory."); + + DBUG_VOID_RETURN; +} + +/* purecov: end */ + + +/** + Initialize the debug sync facility at thread start. + + @param[in] thd thread handle +*/ + +void debug_sync_init_thread(THD *thd) +{ + DBUG_ENTER("debug_sync_init_thread"); + DBUG_ASSERT(thd); + + if (opt_debug_sync_timeout) + { + thd->debug_sync_control= (st_debug_sync_control*) + my_malloc(sizeof(st_debug_sync_control), MYF(MY_WME | MY_ZEROFILL)); + if (!thd->debug_sync_control) + { + /* + Error is reported by my_malloc(). + We must disable the facility. We have no way to return an error. + */ + debug_sync_emergency_disable(); /* purecov: tested */ + } + } + + DBUG_VOID_RETURN; +} + + +/** + End the debug sync facility at thread end. + + @param[in] thd thread handle +*/ + +void debug_sync_end_thread(THD *thd) +{ + DBUG_ENTER("debug_sync_end_thread"); + DBUG_ASSERT(thd); + + if (thd->debug_sync_control) + { + st_debug_sync_control *ds_control= thd->debug_sync_control; + + /* + This synchronization point can be used to synchronize on thread end. + This is the latest point in a THD's life, where this can be done. + */ + DEBUG_SYNC(thd, "thread_end"); + + if (ds_control->ds_action) + { + st_debug_sync_action *action= ds_control->ds_action; + st_debug_sync_action *action_end= action + ds_control->ds_allocated; + for (; action < action_end; action++) + { + action->signal.free(); + action->wait_for.free(); + action->sync_point.free(); + } + my_free(ds_control->ds_action, MYF(0)); + } + + /* Statistics. */ + pthread_mutex_lock(&debug_sync_global.ds_mutex); + debug_sync_global.dsp_hits+= ds_control->dsp_hits; + debug_sync_global.dsp_executed+= ds_control->dsp_executed; + if (debug_sync_global.dsp_max_active < ds_control->dsp_max_active) + debug_sync_global.dsp_max_active= ds_control->dsp_max_active; + pthread_mutex_unlock(&debug_sync_global.ds_mutex); + + my_free(ds_control, MYF(0)); + thd->debug_sync_control= NULL; + } + + DBUG_VOID_RETURN; +} + + +/** + Move a string by length. + + @param[out] to buffer for the resulting string + @param[in] to_end end of buffer + @param[in] from source string + @param[in] length number of bytes to copy + + @return pointer to end of copied string +*/ + +static char *debug_sync_bmove_len(char *to, char *to_end, + const char *from, size_t length) +{ + DBUG_ASSERT(to); + DBUG_ASSERT(to_end); + DBUG_ASSERT(!length || from); + set_if_smaller(length, (size_t) (to_end - to)); + memcpy(to, from, length); + return (to + length); +} + + +#if !defined(DBUG_OFF) + +/** + Create a string that describes an action. + + @param[out] result buffer for the resulting string + @param[in] size size of result buffer + @param[in] action action to describe +*/ + +static void debug_sync_action_string(char *result, uint size, + st_debug_sync_action *action) +{ + char *wtxt= result; + char *wend= wtxt + size - 1; /* Allow emergency '\0'. */ + DBUG_ASSERT(result); + DBUG_ASSERT(action); + + /* If an execute count is present, signal or wait_for are needed too. */ + DBUG_ASSERT(!action->execute || + action->signal.length() || action->wait_for.length()); + + if (action->execute) + { + if (action->signal.length()) + { + wtxt= debug_sync_bmove_len(wtxt, wend, STRING_WITH_LEN("SIGNAL ")); + wtxt= debug_sync_bmove_len(wtxt, wend, action->signal.ptr(), + action->signal.length()); + } + if (action->wait_for.length()) + { + if ((wtxt == result) && (wtxt < wend)) + *(wtxt++)= ' '; + wtxt= debug_sync_bmove_len(wtxt, wend, STRING_WITH_LEN(" WAIT_FOR ")); + wtxt= debug_sync_bmove_len(wtxt, wend, action->wait_for.ptr(), + action->wait_for.length()); + + if (action->timeout != opt_debug_sync_timeout) + { + wtxt+= my_snprintf(wtxt, wend - wtxt, " TIMEOUT %lu", action->timeout); + } + } + if (action->execute != 1) + { + wtxt+= my_snprintf(wtxt, wend - wtxt, " EXECUTE %lu", action->execute); + } + } + if (action->hit_limit) + { + wtxt+= my_snprintf(wtxt, wend - wtxt, "%sHIT_LIMIT %lu", + (wtxt == result) ? "" : " ", action->hit_limit); + } + + /* + If (wtxt == wend) string may not be terminated. + There is one byte left for an emergency termination. + */ + *wtxt= '\0'; +} + + +/** + Print actions. + + @param[in] thd thread handle +*/ + +static void debug_sync_print_actions(THD *thd) +{ + st_debug_sync_control *ds_control= thd->debug_sync_control; + uint idx; + DBUG_ENTER("debug_sync_print_actions"); + DBUG_ASSERT(thd); + + if (!ds_control) + DBUG_VOID_RETURN; + + for (idx= 0; idx < ds_control->ds_active; idx++) + { + const char *dsp_name= ds_control->ds_action[idx].sync_point.c_ptr(); + char action_string[256]; + + debug_sync_action_string(action_string, sizeof(action_string), + ds_control->ds_action + idx); + DBUG_PRINT("debug_sync_list", ("%s %s", dsp_name, action_string)); + } + + DBUG_VOID_RETURN; +} + +#endif /* !defined(DBUG_OFF) */ + + +/** + Compare two actions by sync point name length, string. + + @param[in] arg1 reference to action1 + @param[in] arg2 reference to action2 + + @return difference + @retval == 0 length1/string1 is same as length2/string2 + @retval < 0 length1/string1 is smaller + @retval > 0 length1/string1 is bigger +*/ + +static int debug_sync_qsort_cmp(const void* arg1, const void* arg2) +{ + st_debug_sync_action *action1= (st_debug_sync_action*) arg1; + st_debug_sync_action *action2= (st_debug_sync_action*) arg2; + int diff; + DBUG_ASSERT(action1); + DBUG_ASSERT(action2); + + if (!(diff= action1->sync_point.length() - action2->sync_point.length())) + diff= memcmp(action1->sync_point.ptr(), action2->sync_point.ptr(), + action1->sync_point.length()); + + return diff; +} + + +/** + Find a debug sync action. + + @param[in] actionarr array of debug sync actions + @param[in] quantity number of actions in array + @param[in] dsp_name name of debug sync point to find + @param[in] name_len length of name of debug sync point + + @return action + @retval != NULL found sync point in array + @retval NULL not found + + @description + Binary search. Array needs to be sorted by length, sync point name. +*/ + +static st_debug_sync_action *debug_sync_find(st_debug_sync_action *actionarr, + int quantity, + const char *dsp_name, + uint name_len) +{ + st_debug_sync_action *action; + int low ; + int high ; + int mid ; + int diff ; + DBUG_ASSERT(actionarr); + DBUG_ASSERT(dsp_name); + DBUG_ASSERT(name_len); + + low= 0; + high= quantity; + + while (low < high) + { + mid= (low + high) / 2; + action= actionarr + mid; + if (!(diff= name_len - action->sync_point.length()) && + !(diff= memcmp(dsp_name, action->sync_point.ptr(), name_len))) + return action; + if (diff > 0) + low= mid + 1; + else + high= mid - 1; + } + + if (low < quantity) + { + action= actionarr + low; + if ((name_len == action->sync_point.length()) && + !memcmp(dsp_name, action->sync_point.ptr(), name_len)) + return action; + } + + return NULL; +} + + +/** + Reset the debug sync facility. + + @param[in] thd thread handle + + @description + Remove all actions of this thread. + Clear the global signal. +*/ + +static void debug_sync_reset(THD *thd) +{ + st_debug_sync_control *ds_control= thd->debug_sync_control; + DBUG_ENTER("debug_sync_reset"); + DBUG_ASSERT(thd); + DBUG_ASSERT(ds_control); + + /* Remove all actions of this thread. */ + ds_control->ds_active= 0; + + /* Clear the global signal. */ + pthread_mutex_lock(&debug_sync_global.ds_mutex); + debug_sync_global.ds_signal.length(0); + pthread_mutex_unlock(&debug_sync_global.ds_mutex); + + DBUG_VOID_RETURN; +} + + +/** + Remove a debug sync action. + + @param[in] ds_control control object + @param[in] action action to be removed + + @description + Removing an action mainly means to decrement the ds_active counter. + But if the action is between other active action in the array, then + the array needs to be shrinked. The active actions above the one to + be removed have to be moved down by one slot. +*/ + +static void debug_sync_remove_action(st_debug_sync_control *ds_control, + st_debug_sync_action *action) +{ + uint dsp_idx= action - ds_control->ds_action; + DBUG_ENTER("debug_sync_remove_action"); + DBUG_ASSERT(ds_control); + DBUG_ASSERT(ds_control == current_thd->debug_sync_control); + DBUG_ASSERT(action); + DBUG_ASSERT(dsp_idx < ds_control->ds_active); + + /* Decrement the number of currently active actions. */ + ds_control->ds_active--; + + /* + If this was not the last active action in the array, we need to + shift remaining active actions down to keep the array gap-free. + Otherwise binary search might fail or take longer than necessary at + least. Also new actions are always put to the end of the array. + */ + if (ds_control->ds_active > dsp_idx) + { + /* + Do not make save_action an object of class st_debug_sync_action. + Its destructor would tamper with the String pointers. + */ + uchar save_action[sizeof(st_debug_sync_action)]; + + /* + Copy the to-be-removed action object to temporary storage before + the shift copies the string pointers over. Do not use assignment + because it would use assignment operator methods for the Strings. + This would copy the strings. The shift below overwrite the string + pointers without freeing them first. By using memmove() we save + the pointers, which are overwritten by the shift. + */ + memmove(save_action, action, sizeof(st_debug_sync_action)); + + /* Move actions down. */ + memmove(ds_control->ds_action + dsp_idx, + ds_control->ds_action + dsp_idx + 1, + (ds_control->ds_active - dsp_idx) * + sizeof(st_debug_sync_action)); + + /* + Copy back the saved action object to the now free array slot. This + replaces the double references of String pointers that have been + produced by the shift. Again do not use an assignment operator to + avoid string allocation/copy. + */ + memmove(ds_control->ds_action + ds_control->ds_active, save_action, + sizeof(st_debug_sync_action)); + } + + DBUG_VOID_RETURN; +} + + +/** + Get a debug sync action. + + @param[in] thd thread handle + @param[in] dsp_name debug sync point name + @param[in] name_len length of sync point name + + @return action + @retval != NULL ok + @retval NULL error + + @description + Find the debug sync action for a debug sync point or make a new one. +*/ + +static st_debug_sync_action *debug_sync_get_action(THD *thd, + const char *dsp_name, + uint name_len) +{ + st_debug_sync_control *ds_control= thd->debug_sync_control; + st_debug_sync_action *action; + DBUG_ENTER("debug_sync_get_action"); + DBUG_ASSERT(thd); + DBUG_ASSERT(dsp_name); + DBUG_ASSERT(name_len); + DBUG_ASSERT(ds_control); + DBUG_PRINT("debug_sync", ("sync_point: '%.*s'", (int) name_len, dsp_name)); + DBUG_PRINT("debug_sync", ("active: %u allocated: %u", + ds_control->ds_active, ds_control->ds_allocated)); + + /* There cannot be more active actions than allocated. */ + DBUG_ASSERT(ds_control->ds_active <= ds_control->ds_allocated); + /* If there are active actions, the action array must be present. */ + DBUG_ASSERT(!ds_control->ds_active || ds_control->ds_action); + + /* Try to reuse existing action if there is one for this sync point. */ + if (ds_control->ds_active && + (action= debug_sync_find(ds_control->ds_action, ds_control->ds_active, + dsp_name, name_len))) + { + /* Reuse an already active sync point action. */ + DBUG_ASSERT((uint)(action - ds_control->ds_action) < ds_control->ds_active); + DBUG_PRINT("debug_sync", ("reuse action idx: %ld", + (long) (action - ds_control->ds_action))); + } + else + { + /* Create a new action. */ + int dsp_idx= ds_control->ds_active++; + set_if_bigger(ds_control->dsp_max_active, ds_control->ds_active); + if (ds_control->ds_active > ds_control->ds_allocated) + { + uint new_alloc= ds_control->ds_active + 3; + void *new_action= my_realloc(ds_control->ds_action, + new_alloc * sizeof(st_debug_sync_action), + MYF(MY_WME | MY_ALLOW_ZERO_PTR)); + if (!new_action) + { + /* Error is reported by my_malloc(). */ + goto err; /* purecov: tested */ + } + ds_control->ds_action= (st_debug_sync_action*) new_action; + ds_control->ds_allocated= new_alloc; + /* Clear memory as we do not run string constructors here. */ + bzero((uchar*) (ds_control->ds_action + dsp_idx), + (new_alloc - dsp_idx) * sizeof(st_debug_sync_action)); + } + DBUG_PRINT("debug_sync", ("added action idx: %u", dsp_idx)); + action= ds_control->ds_action + dsp_idx; + if (action->sync_point.copy(dsp_name, name_len, system_charset_info)) + { + /* Error is reported by my_malloc(). */ + goto err; /* purecov: tested */ + } + action->need_sort= TRUE; + } + DBUG_ASSERT(action >= ds_control->ds_action); + DBUG_ASSERT(action < ds_control->ds_action + ds_control->ds_active); + DBUG_PRINT("debug_sync", ("action: 0x%lx array: 0x%lx count: %u", + (long) action, (long) ds_control->ds_action, + ds_control->ds_active)); + + DBUG_RETURN(action); + + /* purecov: begin tested */ + err: + DBUG_RETURN(NULL); + /* purecov: end */ +} + + +/** + Set a debug sync action. + + @param[in] thd thread handle + @param[in] action synchronization action + + @return status + @retval FALSE ok + @retval TRUE error + + @description + This is called from the debug sync parser. It arms the action for + the requested sync point. If the action parsed into an empty action, + it is removed instead. + + Setting an action for a sync point means to make the sync point + active. When it is hit it will execute this action. + + Before parsing, we "get" an action object. This is placed at the + end of the thread's action array unless the requested sync point + has an action already. + + Then the parser fills the action object from the request string. + + Finally the action is "set" for the sync point. If it was parsed + to be empty, it is removed from the array. If it did belong to a + sync point before, the sync point becomes inactive. If the action + became non-empty and it did not belong to a sync point before (it + was added at the end of the action array), the action array needs + to be sorted by sync point. + + If the sync point name is "now", it is executed immediately. +*/ + +static bool debug_sync_set_action(THD *thd, st_debug_sync_action *action) +{ + st_debug_sync_control *ds_control= thd->debug_sync_control; + bool is_dsp_now= FALSE; + DBUG_ENTER("debug_sync_set_action"); + DBUG_ASSERT(thd); + DBUG_ASSERT(action); + DBUG_ASSERT(ds_control); + + action->activation_count= max(action->hit_limit, action->execute); + if (!action->activation_count) + { + debug_sync_remove_action(ds_control, action); + DBUG_PRINT("debug_sync", ("action cleared")); + } + else + { + const char *dsp_name= action->sync_point.c_ptr(); + DBUG_EXECUTE("debug_sync", { + /* Functions as DBUG_PRINT args can change keyword and line nr. */ + const char *sig_emit= action->signal.c_ptr(); + const char *sig_wait= action->wait_for.c_ptr(); + DBUG_PRINT("debug_sync", + ("sync_point: '%s' activation_count: %lu hit_limit: %lu " + "execute: %lu timeout: %lu signal: '%s' wait_for: '%s'", + dsp_name, action->activation_count, + action->hit_limit, action->execute, action->timeout, + sig_emit, sig_wait));}); + + /* Check this before sorting the array. action may move. */ + is_dsp_now= !my_strcasecmp(system_charset_info, dsp_name, "now"); + + if (action->need_sort) + { + action->need_sort= FALSE; + /* Sort actions by (name_len, name). */ + my_qsort(ds_control->ds_action, ds_control->ds_active, + sizeof(st_debug_sync_action), debug_sync_qsort_cmp); + } + } + DBUG_EXECUTE("debug_sync_list", debug_sync_print_actions(thd);); + + /* Execute the special sync point 'now' if activated above. */ + if (is_dsp_now) + { + DEBUG_SYNC(thd, "now"); + /* + If HIT_LIMIT for sync point "now" was 1, the execution of the sync + point decremented it to 0. In this case the following happened: + + - an error message was reported with my_error() and + - the statement was killed with thd->killed= THD::KILL_QUERY. + + If a statement reports an error, it must not call send_ok(). + The calling functions will not call send_ok(), if we return TRUE + from this function. + + thd->killed is also set if the wait is interrupted from a + KILL or KILL QUERY statement. In this case, no error is reported + and shall not be reported as a result of SET DEBUG_SYNC. + Hence, we check for the first condition above. + */ + if (thd->is_error()) + DBUG_RETURN(TRUE); + } + + DBUG_RETURN(FALSE); +} + + +/** + Extract a token from a string. + + @param[out] token_p returns start of token + @param[out] token_length_p returns length of token + @param[in,out] ptr current string pointer, adds '\0' terminators + + @return string pointer or NULL + @retval != NULL ptr behind token terminator or at string end + @retval NULL no token found in remainder of string + + @note + This function assumes that the string is in system_charset_info, + that this charset is single byte for ASCII NUL ('\0'), that no + character except of ASCII NUL ('\0') contains a byte with value 0, + and that ASCII NUL ('\0') is used as the string terminator. + + This function needs to return tokens that are terminated with ASCII + NUL ('\0'). The tokens are used in my_strcasecmp(). Unfortunately + there is no my_strncasecmp(). + + To return the last token without copying it, we require the input + string to be nul terminated. + + @description + This function skips space characters at string begin. + + It returns a pointer to the first non-space character in *token_p. + + If no non-space character is found before the string terminator + ASCII NUL ('\0'), the function returns NULL. *token_p and + *token_length_p remain unchanged in this case (they are not set). + + The function takes a space character or an ASCII NUL ('\0') as a + terminator of the token. The space character could be multi-byte. + + It returns the length of the token in bytes, excluding the + terminator, in *token_length_p. + + If the terminator of the token is ASCII NUL ('\0'), it returns a + pointer to the terminator (string end). + + If the terminator is a space character, it replaces the the first + byte of the terminator character by ASCII NUL ('\0'), skips the (now + corrupted) terminator character, and skips all following space + characters. It returns a pointer to the next non-space character or + to the string terminator ASCII NUL ('\0'). +*/ + +static char *debug_sync_token(char **token_p, uint *token_length_p, char *ptr) +{ + DBUG_ASSERT(token_p); + DBUG_ASSERT(token_length_p); + DBUG_ASSERT(ptr); + + /* Skip leading space */ + while (my_isspace(system_charset_info, *ptr)) + ptr+= my_mbcharlen(system_charset_info, (uchar) *ptr); + + if (!*ptr) + { + ptr= NULL; + goto end; + } + + /* Get token start. */ + *token_p= ptr; + + /* Find token end. */ + while (*ptr && !my_isspace(system_charset_info, *ptr)) + ptr+= my_mbcharlen(system_charset_info, (uchar) *ptr); + + /* Get token length. */ + *token_length_p= ptr - *token_p; + + /* If necessary, terminate token. */ + if (*ptr) + { + /* Get terminator character length. */ + uint mbspacelen= my_mbcharlen(system_charset_info, (uchar) *ptr); + + /* Terminate token. */ + *ptr= '\0'; + + /* Skip the terminator. */ + ptr+= mbspacelen; + + /* Skip trailing space */ + while (my_isspace(system_charset_info, *ptr)) + ptr+= my_mbcharlen(system_charset_info, (uchar) *ptr); + } + + end: + return ptr; +} + + +/** + Extract a number from a string. + + @param[out] number_p returns number + @param[in] actstrptr current pointer in action string + + @return string pointer or NULL + @retval != NULL ptr behind token terminator or at string end + @retval NULL no token found or token is not valid number + + @note + The same assumptions about charset apply as for debug_sync_token(). + + @description + This function fetches a token from the string and converts it + into a number. + + If there is no token left in the string, or the token is not a valid + decimal number, NULL is returned. The result in *number_p is + undefined in this case. +*/ + +static char *debug_sync_number(ulong *number_p, char *actstrptr) +{ + char *ptr; + char *ept; + char *token; + uint token_length; + DBUG_ASSERT(number_p); + DBUG_ASSERT(actstrptr); + + /* Get token from string. */ + if (!(ptr= debug_sync_token(&token, &token_length, actstrptr))) + goto end; + + *number_p= strtoul(token, &ept, 10); + if (*ept) + ptr= NULL; + + end: + return ptr; +} + + +/** + Evaluate a debug sync action string. + + @param[in] thd thread handle + @param[in,out] action_str action string to receive '\0' terminators + + @return status + @retval FALSE ok + @retval TRUE error + + @description + This is called when the DEBUG_SYNC system variable is set. + Parse action string, build a debug sync action, activate it. + + Before parsing, we "get" an action object. This is placed at the + end of the thread's action array unless the requested sync point + has an action already. + + Then the parser fills the action object from the request string. + + Finally the action is "set" for the sync point. This means that the + sync point becomes active or inactive, depending on the action + values. + + @note + The input string needs to be ASCII NUL ('\0') terminated. We split + nul-terminated tokens in it without copy. + + @see the function comment of debug_sync_token() for more constraints + for the string. +*/ + +static bool debug_sync_eval_action(THD *thd, char *action_str) +{ + st_debug_sync_action *action= NULL; + const char *errmsg; + char *ptr; + char *token; + uint token_length= 0; + DBUG_ENTER("debug_sync_eval_action"); + DBUG_ASSERT(thd); + DBUG_ASSERT(action_str); + + /* + Get debug sync point name. Or a special command. + */ + if (!(ptr= debug_sync_token(&token, &token_length, action_str))) + { + errmsg= "Missing synchronization point name"; + goto err; + } + + /* + If there is a second token, the first one is the sync point name. + */ + if (*ptr) + { + /* Get an action object to collect the requested action parameters. */ + action= debug_sync_get_action(thd, token, token_length); + if (!action) + { + /* Error message is sent. */ + DBUG_RETURN(TRUE); /* purecov: tested */ + } + } + + /* + Get kind of action to be taken at sync point. + */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + { + /* No action present. Try special commands. Token unchanged. */ + + /* + Try RESET. + */ + if (!my_strcasecmp(system_charset_info, token, "RESET")) + { + /* It is RESET. Reset all actions and global signal. */ + debug_sync_reset(thd); + goto end; + } + + /* Token unchanged. It still contains sync point name. */ + errmsg= "Missing action after synchronization point name '%.*s'"; + goto err; + } + + /* + Check for pseudo actions first. Start with actions that work on + an existing action. + */ + DBUG_ASSERT(action); + + /* + Try TEST. + */ + if (!my_strcasecmp(system_charset_info, token, "TEST")) + { + /* It is TEST. Nothing must follow it. */ + if (*ptr) + { + errmsg= "Nothing must follow action TEST"; + goto err; + } + + /* Execute sync point. */ + debug_sync(thd, action->sync_point.ptr(), action->sync_point.length()); + /* Fix statistics. This was not a real hit of the sync point. */ + thd->debug_sync_control->dsp_hits--; + goto end; + } + + /* + Now check for actions that define a new action. + Initialize action. Do not use bzero(). Strings may have malloced. + */ + action->activation_count= 0; + action->hit_limit= 0; + action->execute= 0; + action->timeout= 0; + action->signal.length(0); + action->wait_for.length(0); + + /* + Try CLEAR. + */ + if (!my_strcasecmp(system_charset_info, token, "CLEAR")) + { + /* It is CLEAR. Nothing must follow it. */ + if (*ptr) + { + errmsg= "Nothing must follow action CLEAR"; + goto err; + } + + /* Set (clear/remove) action. */ + goto set_action; + } + + /* + Now check for real sync point actions. + */ + + /* + Try SIGNAL. + */ + if (!my_strcasecmp(system_charset_info, token, "SIGNAL")) + { + /* It is SIGNAL. Signal name must follow. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + { + errmsg= "Missing signal name after action SIGNAL"; + goto err; + } + if (action->signal.copy(token, token_length, system_charset_info)) + { + /* Error is reported by my_malloc(). */ + /* purecov: begin tested */ + errmsg= NULL; + goto err; + /* purecov: end */ + } + + /* Set default for EXECUTE option. */ + action->execute= 1; + + /* Get next token. If none follows, set action. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + goto set_action; + } + + /* + Try WAIT_FOR. + */ + if (!my_strcasecmp(system_charset_info, token, "WAIT_FOR")) + { + /* It is WAIT_FOR. Wait_for signal name must follow. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + { + errmsg= "Missing signal name after action WAIT_FOR"; + goto err; + } + if (action->wait_for.copy(token, token_length, system_charset_info)) + { + /* Error is reported by my_malloc(). */ + /* purecov: begin tested */ + errmsg= NULL; + goto err; + /* purecov: end */ + } + + /* Set default for EXECUTE and TIMEOUT options. */ + action->execute= 1; + action->timeout= opt_debug_sync_timeout; + + /* Get next token. If none follows, set action. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + goto set_action; + + /* + Try TIMEOUT. + */ + if (!my_strcasecmp(system_charset_info, token, "TIMEOUT")) + { + /* It is TIMEOUT. Number must follow. */ + if (!(ptr= debug_sync_number(&action->timeout, ptr))) + { + errmsg= "Missing valid number after TIMEOUT"; + goto err; + } + + /* Get next token. If none follows, set action. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + goto set_action; + } + } + + /* + Try EXECUTE. + */ + if (!my_strcasecmp(system_charset_info, token, "EXECUTE")) + { + /* + EXECUTE requires either SIGNAL and/or WAIT_FOR to be present. + In this case action->execute has been preset to 1. + */ + if (!action->execute) + { + errmsg= "Missing action before EXECUTE"; + goto err; + } + + /* Number must follow. */ + if (!(ptr= debug_sync_number(&action->execute, ptr))) + { + errmsg= "Missing valid number after EXECUTE"; + goto err; + } + + /* Get next token. If none follows, set action. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + goto set_action; + } + + /* + Try HIT_LIMIT. + */ + if (!my_strcasecmp(system_charset_info, token, "HIT_LIMIT")) + { + /* Number must follow. */ + if (!(ptr= debug_sync_number(&action->hit_limit, ptr))) + { + errmsg= "Missing valid number after HIT_LIMIT"; + goto err; + } + + /* Get next token. If none follows, set action. */ + if (!(ptr= debug_sync_token(&token, &token_length, ptr))) + goto set_action; + } + + errmsg= "Illegal or out of order stuff: '%.*s'"; + + err: + if (errmsg) + { + /* + NOTE: errmsg must either have %.*s or none % at all. + It can be NULL if an error message is already reported + (e.g. by my_malloc()). + */ + set_if_smaller(token_length, 64); /* Limit error message length. */ + my_printf_error(ER_PARSE_ERROR, errmsg, MYF(0), token_length, token); + } + if (action) + debug_sync_remove_action(thd->debug_sync_control, action); + DBUG_RETURN(TRUE); + + set_action: + DBUG_RETURN(debug_sync_set_action(thd, action)); + + end: + DBUG_RETURN(FALSE); +} + + +/** + Check if the system variable 'debug_sync' can be set. + + @param[in] thd thread handle + @param[in] var set variable request + + @return status + @retval FALSE ok, variable can be set + @retval TRUE error, variable cannot be set +*/ + +bool sys_var_debug_sync::check(THD *thd, set_var *var) +{ + DBUG_ENTER("sys_var_debug_sync::check"); + DBUG_ASSERT(thd); + DBUG_ASSERT(var); + + /* + Variable can be set for the session only. + + This could be changed later. Then we need to have a global array of + actions in addition to the thread local ones. SET GLOBAL would + manage the global array, SET [SESSION] the local array. A sync point + would need to look for a local and a global action. Setting and + executing of global actions need to be protected by a mutex. + + The purpose of global actions could be to allow synchronizing with + connectionless threads that cannot execute SET statements. + */ + if (var->type == OPT_GLOBAL) + { + my_error(ER_LOCAL_VARIABLE, MYF(0), name); + DBUG_RETURN(TRUE); + } + + /* + Do not check for disabled facility. Test result should not + unnecessarily differ from enabled facility. + */ + + /* + Facility requires SUPER privilege. Sync points could be inside + global mutexes (e.g. LOCK_open). Waiting there forever would + stall the whole server. + */ + DBUG_RETURN(check_global_access(thd, SUPER_ACL)); +} + + +/** + Set the system variable 'debug_sync'. + + @param[in] thd thread handle + @param[in] var set variable request + + @return status + @retval FALSE ok, variable is set + @retval TRUE error, variable could not be set + + @note + "Setting" of the system variable 'debug_sync' does not mean to + assign a value to it as usual. Instead a debug sync action is parsed + from the input string and stored apart from the variable value. + + @note + For efficiency reasons, the action string parser places '\0' + terminators in the string. So we need to take a copy here. +*/ + +bool sys_var_debug_sync::update(THD *thd, set_var *var) +{ + char *val_str; + String *val_ptr; + String val_buf; + DBUG_ENTER("sys_var_debug_sync::update"); + DBUG_ASSERT(thd); + + /* + Depending on the value type (string literal, user variable, ...) + val_buf receives a copy of the value or not. But we always need + a copy. So we take a copy, if it is not done by val_str(). + If val_str() puts a copy into val_buf, then it returns &val_buf, + otherwise it returns a pointer to the string object that we need + to copy. + */ + val_ptr= var ? var->value->val_str(&val_buf) : &val_buf; + if (val_ptr != &val_buf) + { + val_buf.copy(*val_ptr); + } + val_str= val_buf.c_ptr(); + DBUG_PRINT("debug_sync", ("set action: '%s'", val_str)); + + /* + debug_sync_eval_action() places '\0' in the string, which itself + must be '\0' terminated. + */ + DBUG_RETURN(opt_debug_sync_timeout ? + debug_sync_eval_action(thd, val_str) : + FALSE); +} + + +/** + Retrieve the value of the system variable 'debug_sync'. + + @param[in] thd thread handle + @param[in] type variable type, unused + @param[in] base variable base, unused + + @return string + @retval != NULL ok, string pointer + @retval NULL memory allocation error + + @note + The value of the system variable 'debug_sync' reflects if + the facility is enabled ("ON") or disabled (default, "OFF"). + + When "ON", the current signal is added. +*/ + +uchar *sys_var_debug_sync::value_ptr(THD *thd, + enum_var_type type __attribute__((unused)), + LEX_STRING *base __attribute__((unused))) +{ + char *value; + DBUG_ENTER("sys_var_debug_sync::value_ptr"); + DBUG_ASSERT(thd); + + if (opt_debug_sync_timeout) + { + static char on[]= "ON - current signal: '"; + + // Ensure exclusive access to debug_sync_global.ds_signal + pthread_mutex_lock(&debug_sync_global.ds_mutex); + + size_t lgt= (sizeof(on) /* includes '\0' */ + + debug_sync_global.ds_signal.length() + 1 /* for '\'' */); + char *vend; + char *vptr; + + if ((value= (char*) alloc_root(thd->mem_root, lgt))) + { + vend= value + lgt - 1; /* reserve space for '\0'. */ + vptr= debug_sync_bmove_len(value, vend, STRING_WITH_LEN(on)); + vptr= debug_sync_bmove_len(vptr, vend, debug_sync_global.ds_signal.ptr(), + debug_sync_global.ds_signal.length()); + if (vptr < vend) + *(vptr++)= '\''; + *vptr= '\0'; /* We have one byte reserved for the worst case. */ + } + pthread_mutex_unlock(&debug_sync_global.ds_mutex); + } + else + { + /* purecov: begin tested */ + value= strmake_root(thd->mem_root, STRING_WITH_LEN("OFF")); + /* purecov: end */ + } + + DBUG_RETURN((uchar*) value); +} + + +/** + Execute requested action at a synchronization point. + + @param[in] thd thread handle + @param[in] action action to be executed + + @note + This is to be called only if activation count > 0. +*/ + +static void debug_sync_execute(THD *thd, st_debug_sync_action *action) +{ + IF_DBUG(const char *dsp_name= action->sync_point.c_ptr()); + IF_DBUG(const char *sig_emit= action->signal.c_ptr()); + IF_DBUG(const char *sig_wait= action->wait_for.c_ptr()); + DBUG_ENTER("debug_sync_execute"); + DBUG_ASSERT(thd); + DBUG_ASSERT(action); + DBUG_PRINT("debug_sync", + ("sync_point: '%s' activation_count: %lu hit_limit: %lu " + "execute: %lu timeout: %lu signal: '%s' wait_for: '%s'", + dsp_name, action->activation_count, action->hit_limit, + action->execute, action->timeout, sig_emit, sig_wait)); + + DBUG_ASSERT(action->activation_count); + action->activation_count--; + + if (action->execute) + { + const char *old_proc_info; + + action->execute--; + + /* + If we will be going to wait, set proc_info for the PROCESSLIST table. + Do this before emitting the signal, so other threads can see it + if they awake before we enter_cond() below. + */ + if (action->wait_for.length()) + { + st_debug_sync_control *ds_control= thd->debug_sync_control; + strxnmov(ds_control->ds_proc_info, sizeof(ds_control->ds_proc_info)-1, + "debug sync point: ", action->sync_point.c_ptr(), NullS); + old_proc_info= thd->proc_info; + thd_proc_info(thd, ds_control->ds_proc_info); + } + + /* + Take mutex to ensure that only one thread access + debug_sync_global.ds_signal at a time. Need to take mutex for + read access too, to create a memory barrier in order to avoid that + threads just reads an old cached version of the signal. + */ + pthread_mutex_lock(&debug_sync_global.ds_mutex); + + if (action->signal.length()) + { + /* Copy the signal to the global variable. */ + if (debug_sync_global.ds_signal.copy(action->signal)) + { + /* + Error is reported by my_malloc(). + We must disable the facility. We have no way to return an error. + */ + debug_sync_emergency_disable(); /* purecov: tested */ + } + /* Wake threads waiting in a sync point. */ + pthread_cond_broadcast(&debug_sync_global.ds_cond); + DBUG_PRINT("debug_sync_exec", ("signal '%s' at: '%s'", + sig_emit, dsp_name)); + } /* end if (action->signal.length()) */ + + if (action->wait_for.length()) + { + pthread_mutex_t *old_mutex; + pthread_cond_t *old_cond; + int error= 0; + struct timespec abstime; + + /* + We don't use enter_cond()/exit_cond(). They do not save old + mutex and cond. This would prohibit the use of DEBUG_SYNC + between other places of enter_cond() and exit_cond(). + */ + old_mutex= thd->mysys_var->current_mutex; + old_cond= thd->mysys_var->current_cond; + thd->mysys_var->current_mutex= &debug_sync_global.ds_mutex; + thd->mysys_var->current_cond= &debug_sync_global.ds_cond; + + set_timespec(abstime, action->timeout); + DBUG_EXECUTE("debug_sync_exec", { + /* Functions as DBUG_PRINT args can change keyword and line nr. */ + const char *sig_glob= debug_sync_global.ds_signal.c_ptr(); + DBUG_PRINT("debug_sync_exec", + ("wait for '%s' at: '%s' curr: '%s'", + sig_wait, dsp_name, sig_glob));}); + + /* + Wait until global signal string matches the wait_for string. + Interrupt when thread or query is killed or facility disabled. + The facility can become disabled when some thread cannot get + the required dynamic memory allocated. + */ + while (stringcmp(&debug_sync_global.ds_signal, &action->wait_for) && + !thd->killed && opt_debug_sync_timeout) + { + error= pthread_cond_timedwait(&debug_sync_global.ds_cond, + &debug_sync_global.ds_mutex, + &abstime); + DBUG_EXECUTE("debug_sync", { + /* Functions as DBUG_PRINT args can change keyword and line nr. */ + const char *sig_glob= debug_sync_global.ds_signal.c_ptr(); + DBUG_PRINT("debug_sync", + ("awoke from %s global: %s error: %d", + sig_wait, sig_glob, error));}); + if (error == ETIMEDOUT || error == ETIME) + { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_DEBUG_SYNC_TIMEOUT, ER(ER_DEBUG_SYNC_TIMEOUT)); + break; + } + error= 0; + } + DBUG_EXECUTE("debug_sync_exec", + if (thd->killed) + DBUG_PRINT("debug_sync_exec", + ("killed %d from '%s' at: '%s'", + thd->killed, sig_wait, dsp_name)); + else + DBUG_PRINT("debug_sync_exec", + ("%s from '%s' at: '%s'", + error ? "timeout" : "resume", + sig_wait, dsp_name));); + + /* + We don't use enter_cond()/exit_cond(). They do not save old + mutex and cond. This would prohibit the use of DEBUG_SYNC + between other places of enter_cond() and exit_cond(). The + protected mutex must always unlocked _before_ mysys_var->mutex + is locked. (See comment in THD::exit_cond().) + */ + pthread_mutex_unlock(&debug_sync_global.ds_mutex); + pthread_mutex_lock(&thd->mysys_var->mutex); + thd->mysys_var->current_mutex= old_mutex; + thd->mysys_var->current_cond= old_cond; + thd_proc_info(thd, old_proc_info); + pthread_mutex_unlock(&thd->mysys_var->mutex); + + } + else + { + /* In case we don't wait, we just release the mutex. */ + pthread_mutex_unlock(&debug_sync_global.ds_mutex); + } /* end if (action->wait_for.length()) */ + + } /* end if (action->execute) */ + + /* hit_limit is zero for infinite. Don't decrement unconditionally. */ + if (action->hit_limit) + { + if (!--action->hit_limit) + { + thd->killed= THD::KILL_QUERY; + my_error(ER_DEBUG_SYNC_HIT_LIMIT, MYF(0)); + } + DBUG_PRINT("debug_sync_exec", ("hit_limit: %lu at: '%s'", + action->hit_limit, dsp_name)); + } + + DBUG_VOID_RETURN; +} + + +/** + Execute requested action at a synchronization point. + + @param[in] thd thread handle + @param[in] sync_point_name name of synchronization point + @param[in] name_len length of sync point name +*/ + +void debug_sync(THD *thd, const char *sync_point_name, size_t name_len) +{ + st_debug_sync_control *ds_control= thd->debug_sync_control; + st_debug_sync_action *action; + DBUG_ENTER("debug_sync"); + DBUG_ASSERT(thd); + DBUG_ASSERT(sync_point_name); + DBUG_ASSERT(name_len); + DBUG_ASSERT(ds_control); + DBUG_PRINT("debug_sync_point", ("hit: '%s'", sync_point_name)); + + /* Statistics. */ + ds_control->dsp_hits++; + + if (ds_control->ds_active && + (action= debug_sync_find(ds_control->ds_action, ds_control->ds_active, + sync_point_name, name_len)) && + action->activation_count) + { + /* Sync point is active (action exists). */ + debug_sync_execute(thd, action); + + /* Statistics. */ + ds_control->dsp_executed++; + + /* If action became inactive, remove it to shrink the search array. */ + if (!action->activation_count) + debug_sync_remove_action(ds_control, action); + } + + DBUG_VOID_RETURN; +} + +#endif /* defined(ENABLED_DEBUG_SYNC) */ diff --git a/sql/debug_sync.h b/sql/debug_sync.h new file mode 100644 index 00000000000..f4cd0b364cf --- /dev/null +++ b/sql/debug_sync.h @@ -0,0 +1,60 @@ +#ifndef DEBUG_SYNC_INCLUDED +#define DEBUG_SYNC_INCLUDED + +/* Copyright (C) 2008 Sun Microsystems, Inc. + + 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 */ + +/** + @file + + Declarations for the Debug Sync Facility. See debug_sync.cc for details. +*/ + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +#include <my_global.h> + +class THD; + +#if defined(ENABLED_DEBUG_SYNC) + +/* Macro to be put in the code at synchronization points. */ +#define DEBUG_SYNC(_thd_, _sync_point_name_) \ + do { if (unlikely(opt_debug_sync_timeout)) \ + debug_sync(_thd_, STRING_WITH_LEN(_sync_point_name_)); \ + } while (0) + +/* Command line option --debug-sync-timeout. See mysqld.cc. */ +extern uint opt_debug_sync_timeout; + +/* Default WAIT_FOR timeout if command line option is given without argument. */ +#define DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT 300 + +/* Debug Sync prototypes. See debug_sync.cc. */ +extern int debug_sync_init(void); +extern void debug_sync_end(void); +extern void debug_sync_init_thread(THD *thd); +extern void debug_sync_end_thread(THD *thd); +extern void debug_sync(THD *thd, const char *sync_point_name, size_t name_len); + +#else /* defined(ENABLED_DEBUG_SYNC) */ + +#define DEBUG_SYNC(_thd_, _sync_point_name_) /* disabled DEBUG_SYNC */ + +#endif /* defined(ENABLED_DEBUG_SYNC) */ + +#endif /* DEBUG_SYNC_INCLUDED */ diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index 331b437b7ff..92427c0ba41 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -1432,7 +1432,7 @@ Event_job_data::execute(THD *thd, bool drop) thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length()); { - Parser_state parser_state(thd, thd->query, thd->query_length); + Parser_state parser_state(thd, thd->query(), thd->query_length()); lex_start(thd); if (parse_sql(thd, & parser_state, creation_ctx)) diff --git a/sql/events.cc b/sql/events.cc index 026d096e2a3..49c7adbaa8e 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -464,7 +464,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, if (!dropped) { /* Binlog the create event. */ - DBUG_ASSERT(thd->query && thd->query_length); + DBUG_ASSERT(thd->query() && thd->query_length()); String log_query; if (create_query_string(thd, &log_query)) { @@ -594,8 +594,8 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, event_queue->update_event(thd, parse_data->dbname, parse_data->name, new_element); /* Binlog the alter event. */ - DBUG_ASSERT(thd->query && thd->query_length); - write_bin_log(thd, TRUE, thd->query, thd->query_length); + DBUG_ASSERT(thd->query() && thd->query_length()); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } } pthread_mutex_unlock(&LOCK_event_metadata); @@ -669,8 +669,8 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists) if (event_queue) event_queue->drop_event(thd, dbname, name); /* Binlog the drop event. */ - DBUG_ASSERT(thd->query && thd->query_length); - write_bin_log(thd, TRUE, thd->query, thd->query_length); + DBUG_ASSERT(thd->query() && thd->query_length()); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } pthread_mutex_unlock(&LOCK_event_metadata); DBUG_RETURN(ret); diff --git a/sql/field.cc b/sql/field.cc index d1202657786..69fe192c1d1 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -2481,97 +2481,12 @@ Field_new_decimal::Field_new_decimal(uint32 len_arg, { precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg); set_if_smaller(precision, DECIMAL_MAX_PRECISION); - DBUG_ASSERT(precision >= dec); DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) && (dec <= DECIMAL_MAX_SCALE)); bin_size= my_decimal_get_binary_size(precision, dec); } -/** - Create a field to hold a decimal value from an item. - - @remark The MySQL DECIMAL data type has a characteristic that needs to be - taken into account when deducing the type from a Item_decimal. - - But first, let's briefly recap what is the new MySQL DECIMAL type: - - The declaration syntax for a decimal is DECIMAL(M,D), where: - - * M is the maximum number of digits (the precision). - It has a range of 1 to 65. - * D is the number of digits to the right of the decimal separator (the scale). - It has a range of 0 to 30 and must be no larger than M. - - D and M are used to determine the storage requirements for the integer - and fractional parts of each value. The integer part is to the left of - the decimal separator and to the right is the fractional part. Hence: - - M is the number of digits for the integer and fractional part. - D is the number of digits for the fractional part. - - Consequently, M - D is the number of digits for the integer part. For - example, a DECIMAL(20,10) column has ten digits on either side of - the decimal separator. - - The characteristic that needs to be taken into account is that the - backing type for Item_decimal is a my_decimal that has a higher - precision (DECIMAL_MAX_POSSIBLE_PRECISION, see my_decimal.h) than - DECIMAL. - - Drawing a comparison between my_decimal and DECIMAL: - - * M has a range of 1 to 81. - * D has a range of 0 to 81. - - There can be a difference in range if the decimal contains a integer - part. This is because the fractional part must always be on a group - boundary, leaving at least one group for the integer part. Since each - group is 9 (DIG_PER_DEC1) digits and there are 9 (DECIMAL_BUFF_LENGTH) - groups, the fractional part is limited to 72 digits if there is at - least one digit in the integral part. - - Although the backing type for a DECIMAL is also my_decimal, every - time a my_decimal is stored in a DECIMAL field, the precision and - scale are explicitly capped at 65 (DECIMAL_MAX_PRECISION) and 30 - (DECIMAL_MAX_SCALE) digits, following my_decimal truncation procedure - (FIX_INTG_FRAC_ERROR). -*/ - -Field_new_decimal * -Field_new_decimal::new_decimal_field(const Item *item) -{ - uint32 len; - uint intg= item->decimal_int_part(), scale= item->decimals; - - DBUG_ASSERT(item->decimal_precision() >= item->decimals); - - /* - Employ a procedure along the lines of the my_decimal truncation process: - - If the integer part is equal to or bigger than the maximum precision: - Truncate integer part to fit and the fractional becomes zero. - - Otherwise: - Truncate fractional part to fit. - */ - if (intg >= DECIMAL_MAX_PRECISION) - { - intg= DECIMAL_MAX_PRECISION; - scale= 0; - } - else - { - uint room= min(DECIMAL_MAX_PRECISION - intg, DECIMAL_MAX_SCALE); - if (scale > room) - scale= room; - } - - len= my_decimal_precision_to_length(intg + scale, scale, item->unsigned_flag); - - return new Field_new_decimal(len, item->maybe_null, item->name, scale, - item->unsigned_flag); -} - - int Field_new_decimal::reset(void) { store_value(&decimal_zero); @@ -6555,20 +6470,9 @@ uint Field::is_equal(Create_field *new_field) } -/* If one of the fields is binary and the other one isn't return 1 else 0 */ - -bool Field_str::compare_str_field_flags(Create_field *new_field, uint32 flag_arg) -{ - return (((new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) && - !(flag_arg & (BINCMP_FLAG | BINARY_FLAG))) || - (!(new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) && - (flag_arg & (BINCMP_FLAG | BINARY_FLAG)))); -} - - uint Field_str::is_equal(Create_field *new_field) { - if (compare_str_field_flags(new_field, flags)) + if (field_flags_are_binary() != new_field->field_flags_are_binary()) return 0; return ((new_field->sql_type == real_type()) && @@ -8334,7 +8238,7 @@ uint Field_blob::max_packed_col_length(uint max_length) uint Field_blob::is_equal(Create_field *new_field) { - if (compare_str_field_flags(new_field, flags)) + if (field_flags_are_binary() != new_field->field_flags_are_binary()) return 0; return ((new_field->sql_type == get_blob_type_from_length(max_data_length())) @@ -8838,38 +8742,81 @@ bool Field::eq_def(Field *field) /** + Compare the first t1::count type names. + + @return TRUE if the type names of t1 match those of t2. FALSE otherwise. +*/ + +static bool compare_type_names(CHARSET_INFO *charset, TYPELIB *t1, TYPELIB *t2) +{ + for (uint i= 0; i < t1->count; i++) + if (my_strnncoll(charset, + (const uchar*) t1->type_names[i], + t1->type_lengths[i], + (const uchar*) t2->type_names[i], + t2->type_lengths[i])) + return FALSE; + return TRUE; +} + +/** @return returns 1 if the fields are equally defined */ bool Field_enum::eq_def(Field *field) { + TYPELIB *values; + if (!Field::eq_def(field)) - return 0; - return compare_enum_values(((Field_enum*) field)->typelib); -} + return FALSE; + values= ((Field_enum*) field)->typelib; -bool Field_enum::compare_enum_values(TYPELIB *values) -{ + /* Definition must be strictly equal. */ if (typelib->count != values->count) return FALSE; - for (uint i= 0; i < typelib->count; i++) - if (my_strnncoll(field_charset, - (const uchar*) typelib->type_names[i], - typelib->type_lengths[i], - (const uchar*) values->type_names[i], - values->type_lengths[i])) - return FALSE; - return TRUE; + + return compare_type_names(field_charset, typelib, values); } +/** + Check whether two fields can be considered 'equal' for table + alteration purposes. Fields are equal if they retain the same + pack length and if new members are added to the end of the list. + + @return IS_EQUAL_YES if fields are compatible. + IS_EQUAL_NO otherwise. +*/ + uint Field_enum::is_equal(Create_field *new_field) { - if (!Field_str::is_equal(new_field)) - return 0; - return compare_enum_values(new_field->interval); + TYPELIB *values= new_field->interval; + + /* + The fields are compatible if they have the same flags, + type, charset and have the same underlying length. + */ + if (new_field->field_flags_are_binary() != field_flags_are_binary() || + new_field->sql_type != real_type() || + new_field->charset != field_charset || + new_field->pack_length != pack_length()) + return IS_EQUAL_NO; + + /* + Changing the definition of an ENUM or SET column by adding a new + enumeration or set members to the end of the list of valid member + values only alters table metadata and not table data. + */ + if (typelib->count > values->count) + return IS_EQUAL_NO; + + /* Check whether there are modification before the end. */ + if (! compare_type_names(field_charset, typelib, new_field->interval)) + return IS_EQUAL_NO; + + return IS_EQUAL_YES; } @@ -9622,7 +9569,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, } if (length == 0) - fld_length= 0; /* purecov: inspected */ + fld_length= NULL; /* purecov: inspected */ } sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1; @@ -9774,8 +9721,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, case MYSQL_TYPE_TIMESTAMP: if (fld_length == NULL) { - /* Compressed date YYYYMMDDHHMMSS */ - length= MAX_DATETIME_COMPRESSED_WIDTH; + length= MAX_DATETIME_WIDTH; } else if (length != MAX_DATETIME_WIDTH) { @@ -9839,7 +9785,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, sql_type= MYSQL_TYPE_NEWDATE; /* fall trough */ case MYSQL_TYPE_NEWDATE: - length= 10; + length= MAX_DATE_WIDTH; break; case MYSQL_TYPE_TIME: length= 10; @@ -9920,6 +9866,17 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, DBUG_RETURN(TRUE); } + switch (fld_type) { + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + charset= &my_charset_bin; + flags|= BINCMP_FLAG; + default: break; + } + DBUG_RETURN(FALSE); /* success */ } diff --git a/sql/field.h b/sql/field.h index 5ac1b35fd81..ce92e75ae61 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008, 2009 Sun Microsystems, Inc. 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 @@ -472,6 +472,13 @@ public: /* maximum possible display length */ virtual uint32 max_display_length()= 0; + /** + Whether a field being created is compatible with a existing one. + + Used by the ALTER TABLE code to evaluate whether the new definition + of a table is compatible with the old definition so that it can + determine if data needs to be copied over (table data change). + */ virtual uint is_equal(Create_field *new_field); /* convert decimal to longlong with overflow check */ longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag, @@ -603,15 +610,17 @@ protected: handle_int64(to, from, low_byte_first_from, table->s->db_low_byte_first); return from + sizeof(int64); } + + bool field_flags_are_binary() + { + return (flags & (BINCMP_FLAG | BINARY_FLAG)) != 0; + } + }; class Field_num :public Field { public: - /** - The scale of the Field's value, i.e. the number of digits to the right - of the decimal point. - */ const uint8 dec; bool zerofill,unsigned_flag; // Purify cannot handle bit fields Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, @@ -662,7 +671,6 @@ public: friend class Create_field; my_decimal *val_decimal(my_decimal *); virtual bool str_needs_quotes() { return TRUE; } - bool compare_str_field_flags(Create_field *new_field, uint32 flags); uint is_equal(Create_field *new_field); }; @@ -770,11 +778,6 @@ public: Field_new_decimal(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, uint8 dec_arg, bool unsigned_arg); - /* - Create a field to hold a decimal value from an item. - Truncates the precision and/or scale if necessary. - */ - static Field_new_decimal *new_decimal_field(const Item *item); enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } Item_result result_type () const { return DECIMAL_RESULT; } @@ -1277,12 +1280,12 @@ public: Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, CHARSET_INFO *cs) - :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg, + :Field_str(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, cs) {} Field_date(bool maybe_null_arg, const char *field_name_arg, CHARSET_INFO *cs) - :Field_str((uchar*) 0,10, maybe_null_arg ? (uchar*) "": 0,0, + :Field_str((uchar*) 0, MAX_DATE_WIDTH, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg, cs) {} enum_field_types type() const { return MYSQL_TYPE_DATE;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } @@ -1392,12 +1395,12 @@ public: Field_datetime(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, CHARSET_INFO *cs) - :Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg, + :Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, cs) {} Field_datetime(bool maybe_null_arg, const char *field_name_arg, CHARSET_INFO *cs) - :Field_str((uchar*) 0,19, maybe_null_arg ? (uchar*) "": 0,0, + :Field_str((uchar*) 0, MAX_DATETIME_WIDTH, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg, cs) {} enum_field_types type() const { return MYSQL_TYPE_DATETIME;} #ifdef HAVE_LONG_LONG @@ -1862,7 +1865,6 @@ public: CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } private: int do_save_field_metadata(uchar *first_byte); - bool compare_enum_values(TYPELIB *values); uint is_equal(Create_field *new_field); }; @@ -2070,6 +2072,11 @@ public: Item *on_update_value, LEX_STRING *comment, char *change, List<String> *interval_list, CHARSET_INFO *cs, uint uint_geom_type); + + bool field_flags_are_binary() + { + return (flags & (BINCMP_FLAG | BINARY_FLAG)) != 0; + } }; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index c6b48c5b744..a3b04ca51da 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -5527,7 +5527,7 @@ int ha_ndbcluster::create(const char *name, if (share && !do_event_op) share->flags|= NSF_NO_BINLOG; ndbcluster_log_schema_op(thd, share, - thd->query, thd->query_length, + thd->query(), thd->query_length(), share->db, share->table_name, m_table->getObjectId(), m_table->getObjectVersion(), @@ -5969,7 +5969,8 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) */ if (!is_old_table_tmpfile) ndbcluster_log_schema_op(current_thd, share, - current_thd->query, current_thd->query_length, + current_thd->query(), + current_thd->query_length(), old_dbname, m_tabname, ndb_table_id, ndb_table_version, SOT_RENAME_TABLE, @@ -6164,7 +6165,7 @@ retry_temporary_error1: current_thd->lex->sql_command != SQLCOM_TRUNCATE) { ndbcluster_log_schema_op(thd, share, - thd->query, thd->query_length, + thd->query(), thd->query_length(), share->db, share->table_name, ndb_table_id, ndb_table_version, SOT_DROP_TABLE, 0, 0, 1); @@ -6887,7 +6888,7 @@ static void ndbcluster_drop_database(handlerton *hton, char *path) THD *thd= current_thd; ha_ndbcluster::set_dbname(path, db); ndbcluster_log_schema_op(thd, 0, - thd->query, thd->query_length, + thd->query(), thd->query_length(), db, "", 0, 0, SOT_DROP_DB, 0, 0, 0); #endif DBUG_VOID_RETURN; @@ -9429,9 +9430,11 @@ ndb_util_thread_fail: pthread_cond_signal(&COND_ndb_util_ready); pthread_mutex_unlock(&LOCK_ndb_util_thread); DBUG_PRINT("exit", ("ndb_util_thread")); + + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); pthread_exit(0); - DBUG_RETURN(NULL); + return NULL; // Avoid compiler warnings } /* @@ -10254,13 +10257,13 @@ int ndbcluster_alter_tablespace(handlerton *hton, #ifdef HAVE_NDB_BINLOG if (is_tablespace) ndbcluster_log_schema_op(thd, 0, - thd->query, thd->query_length, + thd->query(), thd->query_length(), "", alter_info->tablespace_name, 0, 0, SOT_TABLESPACE, 0, 0, 0); else ndbcluster_log_schema_op(thd, 0, - thd->query, thd->query_length, + thd->query(), thd->query_length(), "", alter_info->logfile_group_name, 0, 0, SOT_LOGFILE_GROUP, 0, 0, 0); diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index baca22dffc7..b24b17106c6 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -241,8 +241,8 @@ static void dbug_print_table(const char *info, TABLE *table) static void run_query(THD *thd, char *buf, char *end, const int *no_print_error, my_bool disable_binlog) { - ulong save_thd_query_length= thd->query_length; - char *save_thd_query= thd->query; + ulong save_thd_query_length= thd->query_length(); + char *save_thd_query= thd->query(); ulong save_thread_id= thd->variables.pseudo_thread_id; struct system_status_var save_thd_status_var= thd->status_var; THD_TRANS save_thd_transaction_all= thd->transaction.all; @@ -259,12 +259,12 @@ static void run_query(THD *thd, char *buf, char *end, if (disable_binlog) thd->options&= ~OPTION_BIN_LOG; - DBUG_PRINT("query", ("%s", thd->query)); + DBUG_PRINT("query", ("%s", thd->query())); DBUG_ASSERT(!thd->in_sub_stmt); DBUG_ASSERT(!thd->prelocked_mode); - mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); + mysql_parse(thd, thd->query(), thd->query_length(), &found_semicolon); if (no_print_error && thd->is_slave_error) { @@ -3665,9 +3665,11 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) ndb_binlog_thread_running= -1; pthread_mutex_unlock(&injector_mutex); pthread_cond_signal(&injector_cond); + + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); pthread_exit(0); - DBUG_RETURN(NULL); + return NULL; // Avoid compiler warnings } lex_start(thd); @@ -4378,10 +4380,11 @@ err: (void) pthread_cond_signal(&injector_cond); DBUG_PRINT("exit", ("ndb_binlog_thread")); - my_thread_end(); + DBUG_LEAVE; // Must match DBUG_ENTER() + my_thread_end(); pthread_exit(0); - DBUG_RETURN(NULL); + return NULL; // Avoid compiler warnings } bool diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 4ca6a1103cc..c8361888146 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -239,6 +239,7 @@ void ha_partition::init_handler_variables() m_curr_key_info[0]= NULL; m_curr_key_info[1]= NULL; is_clone= FALSE, + m_part_func_monotonicity_info= NON_MONOTONIC; auto_increment_lock= FALSE; auto_increment_safe_stmt_log_lock= FALSE; /* @@ -705,6 +706,7 @@ int ha_partition::rename_partitions(const char *path) if (m_is_sub_partitioned) { List_iterator<partition_element> sub_it(part_elem->subpartitions); + j= 0; do { sub_elem= sub_it++; @@ -1278,10 +1280,10 @@ void ha_partition::cleanup_new_partition(uint part_count) m_file= m_added_file; m_added_file= NULL; + external_lock(ha_thd(), F_UNLCK); /* delete_table also needed, a bit more complex */ close(); - m_added_file= m_file; m_file= save_m_file; } DBUG_VOID_RETURN; @@ -2464,11 +2466,18 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) } } + /* Initialize the bitmap we use to minimize ha_start_bulk_insert calls */ + if (bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts + 1, FALSE)) + DBUG_RETURN(1); + bitmap_clear_all(&m_bulk_insert_started); /* Initialize the bitmap we use to determine what partitions are used */ if (!is_clone) { if (bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE)) + { + bitmap_free(&m_bulk_insert_started); DBUG_RETURN(1); + } bitmap_set_all(&(m_part_info->used_partitions)); } @@ -2552,12 +2561,18 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) calling open on all individual handlers. */ m_handler_status= handler_opened; + if (m_part_info->part_expr) + m_part_func_monotonicity_info= + m_part_info->part_expr->get_monotonicity_info(); + else if (m_part_info->list_of_part_fields) + m_part_func_monotonicity_info= MONOTONIC_STRICT_INCREASING; info(HA_STATUS_VARIABLE | HA_STATUS_CONST); DBUG_RETURN(0); err_handler: while (file-- != m_file) (*file)->close(); + bitmap_free(&m_bulk_insert_started); if (!is_clone) bitmap_free(&(m_part_info->used_partitions)); @@ -2605,6 +2620,7 @@ int ha_partition::close(void) DBUG_ASSERT(table->s == table_share); delete_queue(&m_queue); + bitmap_free(&m_bulk_insert_started); if (!is_clone) bitmap_free(&(m_part_info->used_partitions)); file= m_file; @@ -3021,10 +3037,12 @@ int ha_partition::write_row(uchar * buf) } m_last_part= part_id; DBUG_PRINT("info", ("Insert in partition %d", part_id)); + start_part_bulk_insert(thd, part_id); + tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ error= m_file[part_id]->ha_write_row(buf); if (have_auto_increment && !table->s->next_number_keypart) - set_auto_increment_if_higher(table->next_number_field->val_int()); + set_auto_increment_if_higher(table->next_number_field); reenable_binlog(thd); exit: table->timestamp_field_type= orig_timestamp_type; @@ -3083,6 +3101,7 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data) } m_last_part= new_part_id; + start_part_bulk_insert(thd, new_part_id); if (new_part_id == old_part_id) { DBUG_PRINT("info", ("Update in partition %d", new_part_id)); @@ -3128,7 +3147,7 @@ exit: HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; if (!ha_data->auto_inc_initialized) info(HA_STATUS_AUTO); - set_auto_increment_if_higher(table->found_next_number_field->val_int()); + set_auto_increment_if_higher(table->found_next_number_field); } table->timestamp_field_type= orig_timestamp_type; DBUG_RETURN(error); @@ -3247,23 +3266,112 @@ int ha_partition::delete_all_rows() DESCRIPTION rows == 0 means we will probably insert many rows */ - void ha_partition::start_bulk_insert(ha_rows rows) { - handler **file; DBUG_ENTER("ha_partition::start_bulk_insert"); - rows= rows ? rows/m_tot_parts + 1 : 0; - file= m_file; - do - { - (*file)->ha_start_bulk_insert(rows); - } while (*(++file)); + m_bulk_inserted_rows= 0; + bitmap_clear_all(&m_bulk_insert_started); + /* use the last bit for marking if bulk_insert_started was called */ + bitmap_set_bit(&m_bulk_insert_started, m_tot_parts); DBUG_VOID_RETURN; } /* + Check if start_bulk_insert has been called for this partition, + if not, call it and mark it called +*/ +void ha_partition::start_part_bulk_insert(THD *thd, uint part_id) +{ + long old_buffer_size; + if (!bitmap_is_set(&m_bulk_insert_started, part_id) && + bitmap_is_set(&m_bulk_insert_started, m_tot_parts)) + { + old_buffer_size= thd->variables.read_buff_size; + /* Update read_buffer_size for this partition */ + thd->variables.read_buff_size= estimate_read_buffer_size(old_buffer_size); + m_file[part_id]->ha_start_bulk_insert(guess_bulk_insert_rows()); + bitmap_set_bit(&m_bulk_insert_started, part_id); + thd->variables.read_buff_size= old_buffer_size; + } + m_bulk_inserted_rows++; +} + +/* + Estimate the read buffer size for each partition. + SYNOPSIS + ha_partition::estimate_read_buffer_size() + original_size read buffer size originally set for the server + RETURN VALUE + estimated buffer size. + DESCRIPTION + If the estimated number of rows to insert is less than 10 (but not 0) + the new buffer size is same as original buffer size. + In case of first partition of when partition function is monotonic + new buffer size is same as the original buffer size. + For rest of the partition total buffer of 10*original_size is divided + equally if number of partition is more than 10 other wise each partition + will be allowed to use original buffer size. +*/ +long ha_partition::estimate_read_buffer_size(long original_size) +{ + /* + If number of rows to insert is less than 10, but not 0, + return original buffer size. + */ + if (estimation_rows_to_insert && (estimation_rows_to_insert < 10)) + return (original_size); + /* + If first insert/partition and monotonic partition function, + allow using buffer size originally set. + */ + if (!m_bulk_inserted_rows && + m_part_func_monotonicity_info != NON_MONOTONIC && + m_tot_parts > 1) + return original_size; + /* + Allow total buffer used in all partition to go up to 10*read_buffer_size. + 11*read_buffer_size in case of monotonic partition function. + */ + + if (m_tot_parts < 10) + return original_size; + return (original_size * 10 / m_tot_parts); +} + +/* + Try to predict the number of inserts into this partition. + + If less than 10 rows (including 0 which means Unknown) + just give that as a guess + If monotonic partitioning function was used + guess that 50 % of the inserts goes to the first partition + For all other cases, guess on equal distribution between the partitions +*/ +ha_rows ha_partition::guess_bulk_insert_rows() +{ + DBUG_ENTER("guess_bulk_insert_rows"); + + if (estimation_rows_to_insert < 10) + DBUG_RETURN(estimation_rows_to_insert); + + /* If first insert/partition and monotonic partition function, guess 50%. */ + if (!m_bulk_inserted_rows && + m_part_func_monotonicity_info != NON_MONOTONIC && + m_tot_parts > 1) + DBUG_RETURN(estimation_rows_to_insert / 2); + + /* Else guess on equal distribution (+1 is to avoid returning 0/Unknown) */ + if (m_bulk_inserted_rows < estimation_rows_to_insert) + DBUG_RETURN(((estimation_rows_to_insert - m_bulk_inserted_rows) + / m_tot_parts) + 1); + /* The estimation was wrong, must say 'Unknown' */ + DBUG_RETURN(0); +} + + +/* Finish a large batch of insert rows SYNOPSIS @@ -3273,21 +3381,29 @@ void ha_partition::start_bulk_insert(ha_rows rows) RETURN VALUE >0 Error code 0 Success + + Note: end_bulk_insert can be called without start_bulk_insert + being called, see bug¤44108. + */ int ha_partition::end_bulk_insert(bool abort) { int error= 0; - handler **file; + uint i; DBUG_ENTER("ha_partition::end_bulk_insert"); - file= m_file; - do + if (!bitmap_is_set(&m_bulk_insert_started, m_tot_parts)) + DBUG_RETURN(error); + + for (i= 0; i < m_tot_parts; i++) { int tmp; - if ((tmp= (*file)->ha_end_bulk_insert(abort))) + if (bitmap_is_set(&m_bulk_insert_started, i) && + (tmp= m_file[i]->ha_end_bulk_insert(abort))) error= tmp; - } while (*(++file)); + } + bitmap_clear_all(&m_bulk_insert_started); DBUG_RETURN(error); } @@ -4896,8 +5012,9 @@ int ha_partition::info(uint flag) If the handler doesn't support statistics, it should set all of the above to 0. - We will allow the first handler to set the rec_per_key and use - this as an estimate on the total table. + We first scans through all partitions to get the one holding most rows. + We will then allow the handler with the most rows to set + the rec_per_key and use this as an estimate on the total table. max_data_file_length: Maximum data file length We ignore it, is only used in @@ -4909,14 +5026,33 @@ int ha_partition::info(uint flag) ref_length: We set this to the value calculated and stored in local object create_time: Creation time of table - Set by first handler - So we calculate these constants by using the variables on the first - handler. + So we calculate these constants by using the variables from the + handler with most rows. */ - handler *file; + handler *file, **file_array; + ulonglong max_records= 0; + uint32 i= 0; + uint32 handler_instance= 0; + + file_array= m_file; + do + { + file= *file_array; + /* Get variables if not already done */ + if (!(flag & HA_STATUS_VARIABLE) || + !bitmap_is_set(&(m_part_info->used_partitions), + (file_array - m_file))) + file->info(HA_STATUS_VARIABLE); + if (file->stats.records > max_records) + { + max_records= file->stats.records; + handler_instance= i; + } + i++; + } while (*(++file_array)); - file= m_file[0]; + file= m_file[handler_instance]; file->info(HA_STATUS_CONST); stats.create_time= file->stats.create_time; ref_length= m_ref_length; diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 3a7084c87ed..5ded3a0f877 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -176,6 +176,11 @@ private: This to ensure it will work with statement based replication. */ bool auto_increment_safe_stmt_log_lock; + /** For optimizing ha_start_bulk_insert calls */ + MY_BITMAP m_bulk_insert_started; + ha_rows m_bulk_inserted_rows; + /** used for prediction of start_bulk_insert rows */ + enum_monotonicity_info m_part_func_monotonicity_info; public: handler *clone(MEM_ROOT *mem_root); virtual void set_part_info(partition_info *part_info) @@ -353,7 +358,6 @@ public: Bulk inserts are supported if all underlying handlers support it. start_bulk_insert and end_bulk_insert is called before and after a number of calls to write_row. - Not yet though. */ virtual int write_row(uchar * buf); virtual int update_row(const uchar * old_data, uchar * new_data); @@ -361,6 +365,11 @@ public: virtual int delete_all_rows(void); virtual void start_bulk_insert(ha_rows rows); virtual int end_bulk_insert(bool); +private: + ha_rows guess_bulk_insert_rows(); + void start_part_bulk_insert(THD *thd, uint part_id); + long estimate_read_buffer_size(long original_size); +public: virtual bool is_fatal_error(int error, uint flags) { @@ -764,10 +773,10 @@ public: if (m_handler_status < handler_initialized || m_handler_status >= handler_closed) DBUG_RETURN(PARTITION_ENABLED_TABLE_FLAGS); - else - DBUG_RETURN((m_file[0]->ha_table_flags() & - ~(PARTITION_DISABLED_TABLE_FLAGS)) | - (PARTITION_ENABLED_TABLE_FLAGS)); + + DBUG_RETURN((m_file[0]->ha_table_flags() & + ~(PARTITION_DISABLED_TABLE_FLAGS)) | + (PARTITION_ENABLED_TABLE_FLAGS)); } /* @@ -936,9 +945,11 @@ private: auto_increment_lock= FALSE; } } - virtual void set_auto_increment_if_higher(const ulonglong nr) + virtual void set_auto_increment_if_higher(Field *field) { HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; + ulonglong nr= (((Field_num*) field)->unsigned_flag || + field->val_int() > 0) ? field->val_int() : 0; lock_auto_increment(); DBUG_ASSERT(ha_data->auto_inc_initialized == TRUE); /* must check when the mutex is taken */ diff --git a/sql/handler.cc b/sql/handler.cc index 4903a93bd3b..28d5914a1d3 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1316,7 +1316,8 @@ int ha_rollback_trans(THD *thd, bool all) } trans->ha_list= 0; trans->no_2pc=0; - if (is_real_trans && thd->transaction_rollback_request) + if (is_real_trans && thd->transaction_rollback_request && + thd->transaction.xid_state.xa_state != XA_NOTR) thd->transaction.xid_state.rm_error= thd->main_da.sql_errno(); if (all) thd->variables.tx_isolation=thd->session_tx_isolation; @@ -1890,12 +1891,42 @@ bool ha_flush_logs(handlerton *db_type) return FALSE; } + +/** + @brief make canonical filename + + @param[in] file table handler + @param[in] path original path + @param[out] tmp_path buffer for canonized path + + @details Lower case db name and table name path parts for + non file based tables when lower_case_table_names + is 2 (store as is, compare in lower case). + Filesystem path prefix (mysql_data_home or tmpdir) + is left intact. + + @note tmp_path may be left intact if no conversion was + performed. + + @retval canonized path + + @todo This may be done more efficiently when table path + gets built. Convert this function to something like + ASSERT_CANONICAL_FILENAME. +*/ const char *get_canonical_filename(handler *file, const char *path, char *tmp_path) { + uint i; if (lower_case_table_names != 2 || (file->ha_table_flags() & HA_FILE_BASED)) return path; + for (i= 0; i <= mysql_tmpdir_list.max; i++) + { + if (is_prefix(path, mysql_tmpdir_list.list[i])) + return path; + } + /* Ensure that table handler get path in lower case */ if (tmp_path != path) strmov(tmp_path, path); @@ -3479,14 +3510,10 @@ int handler::index_next_same(uchar *buf, const uchar *key, uint keylen) if (!(error=index_next(buf))) { my_ptrdiff_t ptrdiff= buf - table->record[0]; - uchar *save_record_0; - KEY *key_info; - KEY_PART_INFO *key_part; - KEY_PART_INFO *key_part_end; - LINT_INIT(save_record_0); - LINT_INIT(key_info); - LINT_INIT(key_part); - LINT_INIT(key_part_end); + uchar *UNINIT_VAR(save_record_0); + KEY *UNINIT_VAR(key_info); + KEY_PART_INFO *UNINIT_VAR(key_part); + KEY_PART_INFO *UNINIT_VAR(key_part_end); /* key_cmp_if_same() compares table->record[0] against 'key'. diff --git a/sql/handler.h b/sql/handler.h index fb1904f23dc..0e4033512d1 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -398,7 +398,6 @@ struct xid_t { my_xid get_my_xid() { return gtrid_length == MYSQL_XID_GTRID_LEN && bqual_length == 0 && - !memcmp(data+MYSQL_XID_PREFIX_LEN, &server_id, sizeof(server_id)) && !memcmp(data, MYSQL_XID_PREFIX, MYSQL_XID_PREFIX_LEN) ? quick_get_my_xid() : 0; } @@ -920,6 +919,15 @@ typedef struct st_ha_create_information ulong key_block_size; SQL_LIST merge_list; handlerton *db_type; + /** + Row type of the table definition. + + Defaults to ROW_TYPE_DEFAULT for all non-ALTER statements. + For ALTER TABLE defaults to ROW_TYPE_NOT_USED (means "keep the current"). + + Can be changed either explicitly by the parser. + If nothing speficied inherits the value of the original table (if present). + */ enum row_type row_type; uint null_bits; /* NULL bits at start of record */ uint options; /* OR of HA_CREATE_ options */ diff --git a/sql/item.cc b/sql/item.cc index b6e8c5dac0b..5160a083cfe 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -433,26 +433,17 @@ Item::Item(THD *thd, Item *item): } -/** - Decimal precision of the item. - - @remark The precision must not be capped as it can be used in conjunction - with Item::decimals to determine the size of the integer part when - constructing a decimal data type. - - @see Item::decimal_int_part() - @see Item::decimals -*/ - uint Item::decimal_precision() const { - uint precision= max_length; Item_result restype= result_type(); if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT)) - precision= my_decimal_length_to_precision(max_length, decimals, unsigned_flag); - - return precision; + { + uint prec= + my_decimal_length_to_precision(max_length, decimals, unsigned_flag); + return min(prec, DECIMAL_MAX_PRECISION); + } + return min(max_length, DECIMAL_MAX_PRECISION); } @@ -4917,7 +4908,9 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length) switch (field_type()) { case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: - field= Field_new_decimal::new_decimal_field(this); + field= new Field_new_decimal((uchar*) 0, max_length, null_ptr, 0, + Field::NONE, name, decimals, 0, + unsigned_flag); break; case MYSQL_TYPE_TINY: field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE, @@ -6340,9 +6333,26 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) /* view fild reference must be defined */ DBUG_ASSERT(*ref); /* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */ - if (!(*ref)->fixed && - ((*ref)->fix_fields(thd, ref))) + if ((*ref)->fixed) + { + Item *ref_item= (*ref)->real_item(); + if (ref_item->type() == Item::FIELD_ITEM) + { + /* + In some cases we need to update table read set(see bug#47150). + If ref item is FIELD_ITEM and fixed then field and table + have proper values. So we can use them for update. + */ + Field *fld= ((Item_field*) ref_item)->field; + DBUG_ASSERT(fld && fld->table); + if (thd->mark_used_columns == MARK_COLUMNS_READ) + bitmap_set_bit(fld->table->read_set, fld->field_index); + } + } + else if (!(*ref)->fixed && + ((*ref)->fix_fields(thd, ref))) return TRUE; + return Item_direct_ref::fix_fields(thd, reference); } @@ -6858,52 +6868,61 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) } /** - Compare the value stored in field, with the original item. + Compare the value stored in field with the expression from the query. - @param field field which the item is converted and stored in - @param item original item + @param field Field which the Item is stored in after conversion + @param item Original expression from query - @return Return an integer greater than, equal to, or less than 0 if - the value stored in the field is greater than, equal to, - or less than the original item + @return Returns an integer greater than, equal to, or less than 0 if + the value stored in the field is greater than, equal to, + or less than the original Item. A 0 may also be returned if + out of memory. @note We only use this on the range optimizer/partition pruning, because in some cases we can't store the value in the field without some precision/character loss. */ -int stored_field_cmp_to_item(Field *field, Item *item) +int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) { - Item_result res_type=item_cmp_type(field->result_type(), item->result_type()); if (res_type == STRING_RESULT) { char item_buff[MAX_FIELD_WIDTH]; char field_buff[MAX_FIELD_WIDTH]; - String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin),*item_result; + + String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin); String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin); - enum_field_types field_type; - item_result=item->val_str(&item_tmp); + String *item_result= item->val_str(&item_tmp); + /* + Some implementations of Item::val_str(String*) actually modify + the field Item::null_value, hence we can't check it earlier. + */ if (item->null_value) return 0; - field->val_str(&field_tmp); + String *field_result= field->val_str(&field_tmp); - /* - If comparing DATE with DATETIME, append the time-part to the DATE. - So that the strings are equally formatted. - A DATE converted to string is 10 characters, and a DATETIME converted - to string is 19 characters. - */ - field_type= field->type(); - if (field_type == MYSQL_TYPE_DATE && - item_result->length() == 19) - field_tmp.append(" 00:00:00"); - else if (field_type == MYSQL_TYPE_DATETIME && - item_result->length() == 10) - item_result->append(" 00:00:00"); - - return stringcmp(&field_tmp,item_result); + enum_field_types field_type= field->type(); + + if (field_type == MYSQL_TYPE_DATE || field_type == MYSQL_TYPE_DATETIME) + { + enum_mysql_timestamp_type type= MYSQL_TIMESTAMP_ERROR; + + if (field_type == MYSQL_TYPE_DATE) + type= MYSQL_TIMESTAMP_DATE; + + if (field_type == MYSQL_TYPE_DATETIME) + type= MYSQL_TIMESTAMP_DATETIME; + + const char *field_name= field->field_name; + MYSQL_TIME field_time, item_time; + get_mysql_time_from_str(thd, field_result, type, field_name, &field_time); + get_mysql_time_from_str(thd, item_result, type, field_name, &item_time); + + return my_time_compare(&field_time, &item_time); + } + return stringcmp(field_result, item_result); } if (res_type == INT_RESULT) return 0; // Both are of type int diff --git a/sql/item.h b/sql/item.h index 84a359e8cd1..91191516fcd 100644 --- a/sql/item.h +++ b/sql/item.h @@ -766,10 +766,9 @@ public: virtual cond_result eq_cmp_result() const { return COND_OK; } inline uint float_length(uint decimals_par) const { return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} - /** Returns the uncapped decimal precision of this item. */ virtual uint decimal_precision() const; inline int decimal_int_part() const - { return decimal_precision() - decimals; } + { return my_decimal_int_part(decimal_precision(), decimals); } /* Returns true if this is constant (during query execution, i.e. its value will not change until next fix_fields) and its value is known. @@ -3160,4 +3159,4 @@ void mark_select_range_as_dependent(THD *thd, extern Cached_item *new_Cached_item(THD *thd, Item *item); extern Item_result item_cmp_type(Item_result a,Item_result b); extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item); -extern int stored_field_cmp_to_item(Field *field, Item *item); +extern int stored_field_cmp_to_item(THD *thd, Field *field, Item *item); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d351fe7d7dc..1844c14a07e 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -189,6 +189,7 @@ enum_field_types agg_field_type(Item **items, uint nitems) collect_cmp_types() items Array of items to collect types from nitems Number of items in the array + skip_nulls Don't collect types of NULL items if TRUE DESCRIPTION This function collects different result types for comparison of the first @@ -199,7 +200,7 @@ enum_field_types agg_field_type(Item **items, uint nitems) Bitmap of collected types - otherwise */ -static uint collect_cmp_types(Item **items, uint nitems) +static uint collect_cmp_types(Item **items, uint nitems, bool skip_nulls= FALSE) { uint i; uint found_types; @@ -208,6 +209,8 @@ static uint collect_cmp_types(Item **items, uint nitems) found_types= 0; for (i= 1; i < nitems ; i++) { + if (skip_nulls && items[i]->type() == Item::NULL_ITEM) + continue; // Skip NULL constant items if ((left_result == ROW_RESULT || items[i]->result_type() == ROW_RESULT) && cmp_row_type(items[0], items[i])) @@ -215,6 +218,12 @@ static uint collect_cmp_types(Item **items, uint nitems) found_types|= 1<< (uint)item_cmp_type(left_result, items[i]->result_type()); } + /* + Even if all right-hand items are NULLs and we are skipping them all, we need + at least one type bit in the found_type bitmask. + */ + if (skip_nulls && !found_types) + found_types= 1 << (uint)left_result; return found_types; } @@ -627,56 +636,51 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) return 0; } - /** - @brief Convert date provided in a string to the int representation. - - @param[in] thd thread handle - @param[in] str a string to convert - @param[in] warn_type type of the timestamp for issuing the warning - @param[in] warn_name field name for issuing the warning - @param[out] error_arg could not extract a DATE or DATETIME - - @details Convert date provided in the string str to the int - representation. If the string contains wrong date or doesn't - contain it at all then a warning is issued. The warn_type and - the warn_name arguments are used as the name and the type of the - field when issuing the warning. If any input was discarded - (trailing or non-timestampy characters), was_cut will be non-zero. - was_type will return the type str_to_datetime() could correctly - extract. - - @return - converted value. 0 on error and on zero-dates -- check 'failure' + Parse date provided in a string to a MYSQL_TIME. + + @param[in] thd Thread handle + @param[in] str A string to convert + @param[in] warn_type Type of the timestamp for issuing the warning + @param[in] warn_name Field name for issuing the warning + @param[out] l_time The MYSQL_TIME objects is initialized. + + Parses a date provided in the string str into a MYSQL_TIME object. If the + string contains an incorrect date or doesn't correspond to a date at all + then a warning is issued. The warn_type and the warn_name arguments are used + as the name and the type of the field when issuing the warning. If any input + was discarded (trailing or non-timestamp-y characters), return value will be + TRUE. + + @return Status flag + @retval FALSE Success. + @retval True Indicates failure. */ -static ulonglong -get_date_from_str(THD *thd, String *str, timestamp_type warn_type, - char *warn_name, bool *error_arg) +bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type, + const char *warn_name, MYSQL_TIME *l_time) { - ulonglong value= 0; + bool value; int error; - MYSQL_TIME l_time; - enum_mysql_timestamp_type ret; + enum_mysql_timestamp_type timestamp_type; - ret= str_to_datetime(str->ptr(), str->length(), &l_time, - (TIME_FUZZY_DATE | MODE_INVALID_DATES | - (thd->variables.sql_mode & - (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))), - &error); + timestamp_type= + str_to_datetime(str->ptr(), str->length(), l_time, + (TIME_FUZZY_DATE | MODE_INVALID_DATES | + (thd->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))), + &error); - if (ret == MYSQL_TIMESTAMP_DATETIME || ret == MYSQL_TIMESTAMP_DATE) - { + if (timestamp_type == MYSQL_TIMESTAMP_DATETIME || + timestamp_type == MYSQL_TIMESTAMP_DATE) /* Do not return yet, we may still want to throw a "trailing garbage" warning. */ - *error_arg= FALSE; - value= TIME_to_ulonglong_datetime(&l_time); - } + value= FALSE; else { - *error_arg= TRUE; + value= TRUE; error= 1; /* force warning */ } @@ -689,6 +693,37 @@ get_date_from_str(THD *thd, String *str, timestamp_type warn_type, } +/** + @brief Convert date provided in a string to the int representation. + + @param[in] thd thread handle + @param[in] str a string to convert + @param[in] warn_type type of the timestamp for issuing the warning + @param[in] warn_name field name for issuing the warning + @param[out] error_arg could not extract a DATE or DATETIME + + @details Convert date provided in the string str to the int + representation. If the string contains wrong date or doesn't + contain it at all then a warning is issued. The warn_type and + the warn_name arguments are used as the name and the type of the + field when issuing the warning. + + @return + converted value. 0 on error and on zero-dates -- check 'failure' +*/ +static ulonglong get_date_from_str(THD *thd, String *str, + timestamp_type warn_type, + const char *warn_name, bool *error_arg) +{ + MYSQL_TIME l_time; + *error_arg= get_mysql_time_from_str(thd, str, warn_type, warn_name, &l_time); + + if (*error_arg) + return 0; + return TIME_to_ulonglong_datetime(&l_time); +} + + /* Check whether compare_datetime() can be used to compare items. @@ -1549,61 +1584,73 @@ longlong Item_in_optimizer::val_int() if (cache->null_value) { + /* + We're evaluating + "<outer_value_list> [NOT] IN (SELECT <inner_value_list>...)" + where one or more of the outer values is NULL. + */ if (((Item_in_subselect*)args[1])->is_top_level_item()) { /* - We're evaluating "NULL IN (SELECT ...)". The result can be NULL or - FALSE, and we can return one instead of another. Just return NULL. + We're evaluating a top level item, e.g. + "<outer_value_list> IN (SELECT <inner_value_list>...)", + and in this case a NULL value in the outer_value_list means + that the result shall be NULL/FALSE (makes no difference for + top level items). The cached value is NULL, so just return + NULL. */ null_value= 1; } else { - if (!((Item_in_subselect*)args[1])->is_correlated && - result_for_null_param != UNKNOWN) + /* + We're evaluating an item where a NULL value in either the + outer or inner value list does not automatically mean that we + can return NULL/FALSE. An example of such a query is + "<outer_value_list> NOT IN (SELECT <inner_value_list>...)" + The result when there is at least one NULL value is: NULL if the + SELECT evaluated over the non-NULL values produces at least + one row, FALSE otherwise + */ + Item_in_subselect *item_subs=(Item_in_subselect*)args[1]; + bool all_left_cols_null= true; + const uint ncols= cache->cols(); + + /* + Turn off the predicates that are based on column compares for + which the left part is currently NULL + */ + for (uint i= 0; i < ncols; i++) { - /* Use cached value from previous execution */ - null_value= result_for_null_param; + if (cache->element_index(i)->null_value) + item_subs->set_cond_guard_var(i, FALSE); + else + all_left_cols_null= false; } - else + + if (!((Item_in_subselect*)args[1])->is_correlated && + all_left_cols_null && result_for_null_param != UNKNOWN) { - /* - We're evaluating "NULL IN (SELECT ...)". The result is: - FALSE if SELECT produces an empty set, or - NULL otherwise. - We disable the predicates we've pushed down into subselect, run the - subselect and see if it has produced any rows. + /* + This is a non-correlated subquery, all values in the outer + value list are NULL, and we have already evaluated the + subquery for all NULL values: Return the same result we + did last time without evaluating the subquery. */ - Item_in_subselect *item_subs=(Item_in_subselect*)args[1]; - if (cache->cols() == 1) - { - item_subs->set_cond_guard_var(0, FALSE); - (void) args[1]->val_bool_result(); - result_for_null_param= null_value= !item_subs->engine->no_rows(); - item_subs->set_cond_guard_var(0, TRUE); - } - else - { - uint i; - uint ncols= cache->cols(); - /* - Turn off the predicates that are based on column compares for - which the left part is currently NULL - */ - for (i= 0; i < ncols; i++) - { - if (cache->element_index(i)->null_value) - item_subs->set_cond_guard_var(i, FALSE); - } - - (void) args[1]->val_bool_result(); - result_for_null_param= null_value= !item_subs->engine->no_rows(); - - /* Turn all predicates back on */ - for (i= 0; i < ncols; i++) - item_subs->set_cond_guard_var(i, TRUE); - } + null_value= result_for_null_param; + } + else + { + /* The subquery has to be evaluated */ + (void) args[1]->val_bool_result(); + null_value= !item_subs->engine->no_rows(); + if (all_left_cols_null) + result_for_null_param= null_value; } + + /* Turn all predicates back on */ + for (uint i= 0; i < ncols; i++) + item_subs->set_cond_guard_var(i, TRUE); } return 0; } @@ -2181,7 +2228,7 @@ uint Item_func_ifnull::decimal_precision() const int arg1_int_part= args[1]->decimal_int_part(); int max_int_part= max(arg0_int_part, arg1_int_part); int precision= max_int_part + decimals; - return precision; + return min(precision, DECIMAL_MAX_PRECISION); } @@ -2365,7 +2412,7 @@ uint Item_func_if::decimal_precision() const int arg1_prec= args[1]->decimal_int_part(); int arg2_prec= args[2]->decimal_int_part(); int precision=max(arg1_prec,arg2_prec) + decimals; - return precision; + return min(precision, DECIMAL_MAX_PRECISION); } @@ -2782,7 +2829,7 @@ uint Item_func_case::decimal_precision() const if (else_expr_num != -1) set_if_bigger(max_int_part, args[else_expr_num]->decimal_int_part()); - return max_int_part + decimals; + return min(max_int_part + decimals, DECIMAL_MAX_PRECISION); } @@ -3523,7 +3570,7 @@ void Item_func_in::fix_length_and_dec() uint type_cnt= 0, i; Item_result cmp_type= STRING_RESULT; left_result_type= args[0]->result_type(); - if (!(found_types= collect_cmp_types(args, arg_count))) + if (!(found_types= collect_cmp_types(args, arg_count, true))) return; for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++) @@ -3701,9 +3748,11 @@ void Item_func_in::fix_length_and_dec() uint j=0; for (uint i=1 ; i < arg_count ; i++) { - array->set(j,args[i]); if (!args[i]->null_value) // Skip NULL values + { + array->set(j,args[i]); j++; + } else have_null= 1; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 23f505182dd..618167a2bd0 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1722,3 +1722,6 @@ inline Item *and_conds(Item *a, Item *b) } Item *and_expressions(Item *a, Item *b, Item **org_item); + +bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type, + const char *warn_name, MYSQL_TIME *l_time); diff --git a/sql/item_func.cc b/sql/item_func.cc index d2b1634ba5e..45d874b9cd9 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -435,8 +435,7 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const Field *Item_func::tmp_table_field(TABLE *table) { - Field *field; - LINT_INIT(field); + Field *field= NULL; switch (result_type()) { case INT_RESULT: @@ -451,8 +450,45 @@ Field *Item_func::tmp_table_field(TABLE *table) case STRING_RESULT: return make_string_field(table); case DECIMAL_RESULT: - field= Field_new_decimal::new_decimal_field(this); + { + uint8 dec= decimals; + uint8 intg= decimal_precision() - dec; + uint32 len= max_length; + + /* + Trying to put too many digits overall in a DECIMAL(prec,dec) + will always throw a warning. We must limit dec to + DECIMAL_MAX_SCALE however to prevent an assert() later. + */ + + if (dec > 0) + { + int overflow; + + dec= min(dec, DECIMAL_MAX_SCALE); + + /* + If the value still overflows the field with the corrected dec, + we'll throw out decimals rather than integers. This is still + bad and of course throws a truncation warning. + */ + + const int required_length= + my_decimal_precision_to_length(intg + dec, dec, + unsigned_flag); + + overflow= required_length - len; + + if (overflow > 0) + dec= max(0, dec - overflow); // too long, discard fract + else + /* Corrected value fits. */ + len= required_length; + } + + field= new Field_new_decimal(len, maybe_null, name, dec, unsigned_flag); break; + } case ROW_RESULT: default: // This case should never be chosen @@ -4239,9 +4275,8 @@ void Item_func_set_user_var::save_item_result(Item *item) bool Item_func_set_user_var::update() { - bool res; + bool res= 0; DBUG_ENTER("Item_func_set_user_var::update"); - LINT_INIT(res); switch (cached_result_type) { case REAL_RESULT: @@ -4744,19 +4779,6 @@ void Item_func_get_user_var::fix_length_and_dec() } -uint Item_func_get_user_var::decimal_precision() const -{ - uint precision= max_length; - Item_result restype= result_type(); - - /* Default to maximum as the precision is unknown a priori. */ - if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT)) - precision= DECIMAL_MAX_PRECISION; - - return precision; -} - - bool Item_func_get_user_var::const_item() const { return (!var_entry || current_thd->query_id != var_entry->update_query_id); diff --git a/sql/item_func.h b/sql/item_func.h index 2e00ac99429..eee3a7ef0f6 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1393,7 +1393,6 @@ public: table_map used_tables() const { return const_item() ? 0 : RAND_TABLE_BIT; } bool eq(const Item *item, bool binary_cmp) const; - uint decimal_precision() const; private: bool set_value(THD *thd, sp_rcontext *ctx, Item **it); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index a34204b7181..3c5990eb359 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -84,7 +84,9 @@ String *Item_func_geometry_from_wkb::val_str(String *str) if (args[0]->field_type() == MYSQL_TYPE_GEOMETRY) { - return args[0]->val_str(str); + String *str_ret= args[0]->val_str(str); + null_value= args[0]->null_value; + return str_ret; } wkb= args[0]->val_str(&arg_val); @@ -94,7 +96,10 @@ String *Item_func_geometry_from_wkb::val_str(String *str) str->set_charset(&my_charset_bin); if (str->reserve(SRID_SIZE, 512)) - return 0; + { + null_value= TRUE; /* purecov: inspected */ + return 0; /* purecov: inspected */ + } str->length(0); str->q_append(srid); if ((null_value= diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 8efc3c98328..5e2c161bbe2 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -632,6 +632,7 @@ String *Item_func_concat_ws::val_str(String *str) String tmp_sep_str(tmp_str_buff, sizeof(tmp_str_buff),default_charset_info), *sep_str, *res, *res2,*use_as_buff; uint i; + bool is_const= 0; null_value=0; if (!(sep_str= args[0]->val_str(&tmp_sep_str))) @@ -645,7 +646,11 @@ String *Item_func_concat_ws::val_str(String *str) // If not, return the empty string for (i=1; i < arg_count; i++) if ((res= args[i]->val_str(str))) + { + is_const= args[i]->const_item() || !args[i]->used_tables(); break; + } + if (i == arg_count) return &my_empty_string; @@ -663,7 +668,7 @@ String *Item_func_concat_ws::val_str(String *str) current_thd->variables.max_allowed_packet); goto null; } - if (res->alloced_length() >= + if (!is_const && res->alloced_length() >= res->length() + sep_str->length() + res2->length()) { // Use old buffer res->append(*sep_str); // res->length() > 0 always diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 7ee22fb3c1c..e3cf96d29ca 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -159,17 +159,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) return TRUE; in_fix_fields++; - res= engine->prepare(); - // all transformation is done (used by prepared statements) - changed= 1; - - if (!res) + if (!(res= engine->prepare())) { + // all transformation is done (used by prepared statements) + changed= 1; + if (substitution) { - int ret= 0; - // did we changed top item of WHERE condition if (unit->outer_select()->where == (*ref)) unit->outer_select()->where= substitution; // correct WHERE for PS @@ -183,22 +180,20 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) substitution= 0; thd->where= "checking transformed subquery"; if (!(*ref)->fixed) - ret= (*ref)->fix_fields(thd, ref); - thd->where= save_where; - in_fix_fields--; - return ret; + res= (*ref)->fix_fields(thd, ref); + goto end; } // Is it one field subselect? if (engine->cols() > max_columns) { my_error(ER_OPERAND_COLUMNS, MYF(0), 1); - in_fix_fields--; - return TRUE; + res= 1; + goto end; } fix_length_and_dec(); } else - goto err; + goto end; if ((uncacheable= engine->uncacheable())) { @@ -208,7 +203,7 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) } fixed= 1; -err: +end: in_fix_fields--; thd->where= save_where; return res; @@ -339,9 +334,14 @@ void Item_subselect::update_used_tables() void Item_subselect::print(String *str, enum_query_type query_type) { - str->append('('); - engine->print(str, query_type); - str->append(')'); + if (engine) + { + str->append('('); + engine->print(str, query_type); + str->append(')'); + } + else + str->append("(...)"); } @@ -1977,6 +1977,7 @@ int subselect_single_select_engine::exec() tab->read_record.record= tab->table->record[0]; tab->read_record.thd= join->thd; tab->read_record.ref_length= tab->table->file->ref_length; + tab->read_record.unlock_row= rr_unlock_row; *(last_changed_tab++)= tab; break; } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index ff70c2aedfc..ab2da503209 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -517,7 +517,8 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, name, table->s, collation.collation); break; case DECIMAL_RESULT: - field= Field_new_decimal::new_decimal_field(this); + field= new Field_new_decimal(max_length, maybe_null, name, + decimals, unsigned_flag); break; case ROW_RESULT: default: diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 33a00cdd8c0..67929de5073 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -278,9 +278,9 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, int strict_week_number_year= -1; int frac_part; bool usa_time= 0; - bool sunday_first_n_first_week_non_iso; - bool strict_week_number; - bool strict_week_number_year_type; + bool UNINIT_VAR(sunday_first_n_first_week_non_iso); + bool UNINIT_VAR(strict_week_number); + bool UNINIT_VAR(strict_week_number_year_type); const char *val_begin= val; const char *val_end= val + length; const char *ptr= format->format.str; @@ -1350,15 +1350,11 @@ bool get_interval_value(Item *args,interval_type int_type, String *str_value, INTERVAL *interval) { ulonglong array[5]; - longlong value; - const char *str; - size_t length; + longlong UNINIT_VAR(value); + const char *UNINIT_VAR(str); + size_t UNINIT_VAR(length); CHARSET_INFO *cs=str_value->charset(); - LINT_INIT(value); - LINT_INIT(str); - LINT_INIT(length); - bzero((char*) interval,sizeof(*interval)); if ((int) int_type <= INTERVAL_MICROSECOND) { diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 8a5804ffd63..100192cd091 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -1354,8 +1354,7 @@ my_xpath_lex_scan(MY_XPATH *xpath, MY_XPATH_LEX *lex, const char *beg, const char *end) { int ch, ctype, length; - for ( ; beg < end && *beg == ' ' ; beg++) // skip leading spaces - ; + for ( ; beg < end && *beg == ' ' ; beg++) ; // skip leading spaces lex->beg= beg; if (beg >= end) @@ -1424,8 +1423,7 @@ my_xpath_lex_scan(MY_XPATH *xpath, if (my_xdigit(ch)) // a sequence of digits { - for ( ; beg < end && my_xdigit(*beg) ; beg++) - ; + for ( ; beg < end && my_xdigit(*beg) ; beg++) ; lex->end= beg; lex->term= MY_XPATH_LEX_DIGITS; return; @@ -1433,8 +1431,7 @@ my_xpath_lex_scan(MY_XPATH *xpath, if (ch == '"' || ch == '\'') // a string: either '...' or "..." { - for ( ; beg < end && *beg != ch ; beg++) - ; + for ( ; beg < end && *beg != ch ; beg++) ; if (beg < end) { lex->end= beg+1; diff --git a/sql/log.cc b/sql/log.cc index af1c4b79464..9ed594bfb36 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -153,7 +153,7 @@ private: class binlog_trx_data { public: binlog_trx_data() - : at_least_one_stmt(0), incident(FALSE), m_pending(0), + : at_least_one_stmt_committed(0), incident(FALSE), m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF) { trans_log.end_of_file= max_binlog_cache_size; @@ -182,7 +182,10 @@ public: { DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos)); DBUG_PRINT("info", ("before_stmt_pos=%lu", (ulong) pos)); - delete pending(); + if (pending()) + { + delete pending(); + } set_pending(0); reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0); trans_log.end_of_file= max_binlog_cache_size; @@ -192,12 +195,12 @@ public: /* The only valid positions that can be truncated to are at the beginning of a statement. We are relying on this fact to be able - to set the at_least_one_stmt flag correctly. In other word, if + to set the at_least_one_stmt_committed flag correctly. In other word, if we are truncating to the beginning of the transaction cache, there will be no statements in the cache, otherwhise, we will have at least one statement in the transaction cache. */ - at_least_one_stmt= (pos > 0); + at_least_one_stmt_committed= (pos > 0); } /* @@ -239,7 +242,7 @@ public: Boolean that is true if there is at least one statement in the transaction cache. */ - bool at_least_one_stmt; + bool at_least_one_stmt_committed; bool incident; private: @@ -1035,14 +1038,10 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command, Log_event_handler **current_handler= general_log_handler_list; char user_host_buff[MAX_USER_HOST_SIZE + 1]; Security_context *sctx= thd->security_ctx; - ulong id; uint user_host_len= 0; time_t current_time; - if (thd) - id= thd->thread_id; /* Normal thread */ - else - id= 0; /* Log from connect handler */ + DBUG_ASSERT(thd); lock_shared(); if (!opt_log) @@ -1061,7 +1060,7 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command, while (*current_handler) error|= (*current_handler++)-> log_general(thd, current_time, user_host_buff, - user_host_len, id, + user_host_len, thd->thread_id, command_name[(uint) command].str, command_name[(uint) command].length, query, query_length, @@ -1287,7 +1286,7 @@ static bool stmt_has_updated_trans_table(THD *thd) { Ha_trx_info *ha_info; - for (ha_info= thd->transaction.stmt.ha_list; ha_info; ha_info= ha_info->next()) + for (ha_info= thd->transaction.stmt.ha_list; ha_info && ha_info->is_started(); ha_info= ha_info->next()) { if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton) return (TRUE); @@ -1535,9 +1534,9 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) /* We commit the transaction if: - - We are not in a transaction and committing a statement, or + - We are not in a transaction and committing a statement, or - - We are in a transaction and a full transaction is committed + - We are in a transaction and a full transaction is committed Otherwise, we accumulate the statement */ @@ -1550,21 +1549,18 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) YESNO(in_transaction), YESNO(thd->transaction.all.modified_non_trans_table), YESNO(thd->transaction.stmt.modified_non_trans_table))); - if (thd->options & OPTION_BIN_LOG) - { - if (!in_transaction || all) - { - Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, TRUE, 0); - error= binlog_end_trans(thd, trx_data, &qev, all); - goto end; - } - } - else + + if (!in_transaction || all || + (!all && !trx_data->at_least_one_stmt_committed && + !stmt_has_updated_trans_table(thd) && + thd->transaction.stmt.modified_non_trans_table)) { - trx_data->reset(); + Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, TRUE, 0); + error= binlog_end_trans(thd, trx_data, &qev, all); } -end: + trx_data->at_least_one_stmt_committed = my_b_tell(&trx_data->trans_log) > 0; + if (!all) trx_data->before_stmt_pos = MY_OFF_T_UNDEF; // part of the stmt commit DBUG_RETURN(error); @@ -1630,15 +1626,18 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) { /* We flush the cache with a rollback, wrapped in a beging/rollback if: - . aborting a transcation that modified a non-transactional table or; + . aborting a transaction that modified a non-transactional table; . aborting a statement that modified both transactional and - non-transctional tables but which is not in the boundaries of any - transaction; + non-transactional tables but which is not in the boundaries of any + transaction or there was no early change; . the OPTION_KEEP_LOG is activate. */ if ((all && thd->transaction.all.modified_non_trans_table) || (!all && thd->transaction.stmt.modified_non_trans_table && !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) || + (!all && thd->transaction.stmt.modified_non_trans_table && + !trx_data->at_least_one_stmt_committed && + thd->current_stmt_binlog_row_based) || ((thd->options & OPTION_KEEP_LOG))) { Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, TRUE, 0); @@ -1730,7 +1729,7 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); int const error= thd->binlog_query(THD::STMT_QUERY_TYPE, - thd->query, thd->query_length, TRUE, FALSE, errcode); + thd->query(), thd->query_length(), TRUE, FALSE, errcode); DBUG_RETURN(error); } @@ -1749,7 +1748,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); int error= thd->binlog_query(THD::STMT_QUERY_TYPE, - thd->query, thd->query_length, TRUE, FALSE, errcode); + thd->query(), thd->query_length(), TRUE, FALSE, errcode); DBUG_RETURN(error); } binlog_trans_log_truncate(thd, *(my_off_t*)sv); @@ -3641,7 +3640,7 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) } old_name=name; name=0; // Don't free name - close(LOG_CLOSE_TO_BE_OPENED); + close(LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX); /* Note that at this point, log_state != LOG_CLOSED (important for is_open()). @@ -3656,8 +3655,10 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) trigger temp tables deletion on slaves. */ - open(old_name, log_type, new_name_ptr, - io_cache_type, no_auto_events, max_size, 1); + /* reopen index binlog file, BUG#34582 */ + if (!open_index_file(index_file_name, 0)) + open(old_name, log_type, new_name_ptr, + io_cache_type, no_auto_events, max_size, 1); my_free(old_name,MYF(0)); end: @@ -4096,8 +4097,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) binlog_[wild_]{do|ignore}_table?" (WL#1049)" */ const char *local_db= event_info->get_db(); - if ((thd && !(thd->options & OPTION_BIN_LOG)) || - (!binlog_filter->db_ok(local_db))) + if ((!(thd->options & OPTION_BIN_LOG)) || + (!binlog_filter->db_ok(local_db))) { VOID(pthread_mutex_unlock(&LOCK_log)); DBUG_RETURN(0); diff --git a/sql/log_event.cc b/sql/log_event.cc index 6aa5365a708..ac2b2e70f20 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1851,6 +1851,7 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td, { const uchar *value0= value; const uchar *null_bits= value; + uint null_bit_index= 0; char typestr[64]= ""; value+= (m_width + 7) / 8; @@ -1859,7 +1860,8 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td, for (size_t i= 0; i < td->size(); i ++) { - int is_null= (null_bits[i / 8] >> (i % 8)) & 0x01; + int is_null= (null_bits[null_bit_index / 8] + >> (null_bit_index % 8)) & 0x01; if (bitmap_is_set(cols_bitmap, i) == 0) continue; @@ -1896,6 +1898,8 @@ Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td, } my_b_printf(file, "\n"); + + null_bit_index++; } return value - value0; } @@ -3038,7 +3042,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, thd->query_id = next_query_id(); VOID(pthread_mutex_unlock(&LOCK_thread_count)); thd->variables.pseudo_thread_id= thread_id; // for temp tables - DBUG_PRINT("query",("%s",thd->query)); + DBUG_PRINT("query",("%s", thd->query())); if (ignored_error_code((expected_error= error_code)) || !unexpected_error_code(expected_error)) @@ -3132,7 +3136,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, /* Execute the query (note that we bypass dispatch_command()) */ const char* found_semicolon= NULL; - mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); + mysql_parse(thd, thd->query(), thd->query_length(), &found_semicolon); log_slow_statement(thd); } else @@ -3144,7 +3148,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, we exit gracefully; otherwise we warn about the bad error and tell DBA to check/fix it. */ - if (mysql_test_parse_for_slave(thd, thd->query, thd->query_length)) + if (mysql_test_parse_for_slave(thd, thd->query(), thd->query_length())) clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); /* Can ignore query */ else { @@ -3154,7 +3158,7 @@ Query partially completed on the master (error on master: %d) \ and was aborted. There is a chance that your master is inconsistent at this \ point. If you are sure that your master is ok, run this query manually on the \ slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; \ -START SLAVE; . Query: '%s'", expected_error, thd->query); +START SLAVE; . Query: '%s'", expected_error, thd->query()); thd->is_slave_error= 1; } goto end; @@ -3162,7 +3166,7 @@ START SLAVE; . Query: '%s'", expected_error, thd->query); /* If the query was not ignored, it is printed to the general log */ if (!thd->is_error() || thd->main_da.sql_errno() != ER_SLAVE_IGNORED_TABLE) - general_log_write(thd, COM_QUERY, thd->query, thd->query_length); + general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); compare_errors: @@ -3854,6 +3858,7 @@ bool Format_description_log_event::write(IO_CACHE* file) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Format_description_log_event::do_apply_event(Relay_log_info const *rli) { + int ret= 0; DBUG_ENTER("Format_description_log_event::do_apply_event"); #ifdef USING_TRANSACTIONS @@ -3895,17 +3900,21 @@ int Format_description_log_event::do_apply_event(Relay_log_info const *rli) 0, then 96, then jump to first really asked event (which is >96). So this is ok. */ - DBUG_RETURN(Start_log_event_v3::do_apply_event(rli)); + ret= Start_log_event_v3::do_apply_event(rli); } - DBUG_RETURN(0); + + if (!ret) + { + /* Save the information describing this binlog */ + delete rli->relay_log.description_event_for_exec; + const_cast<Relay_log_info *>(rli)->relay_log.description_event_for_exec= this; + } + + DBUG_RETURN(ret); } int Format_description_log_event::do_update_pos(Relay_log_info *rli) { - /* save the information describing this binlog */ - delete rli->relay_log.description_event_for_exec; - rli->relay_log.description_event_for_exec= this; - if (server_id == (uint32) ::server_id) { /* @@ -4009,7 +4018,7 @@ uint Load_log_event::get_query_buffer_length() } -void Load_log_event::print_query(bool need_db, char *buf, +void Load_log_event::print_query(bool need_db, const char *cs, char *buf, char **end, char **fn_start, char **fn_end) { char *pos= buf; @@ -4033,9 +4042,9 @@ void Load_log_event::print_query(bool need_db, char *buf, pos= strmov(pos+fname_len, "' "); if (sql_ex.opt_flags & REPLACE_FLAG) - pos= strmov(pos, " REPLACE "); + pos= strmov(pos, "REPLACE "); else if (sql_ex.opt_flags & IGNORE_FLAG) - pos= strmov(pos, " IGNORE "); + pos= strmov(pos, "IGNORE "); pos= strmov(pos ,"INTO"); @@ -4046,8 +4055,16 @@ void Load_log_event::print_query(bool need_db, char *buf, memcpy(pos, table_name, table_name_len); pos+= table_name_len; - /* We have to create all optinal fields as the default is not empty */ - pos= strmov(pos, "` FIELDS TERMINATED BY "); + if (cs != NULL) + { + pos= strmov(pos ,"` CHARACTER SET "); + pos= strmov(pos , cs); + } + else + pos= strmov(pos, "`"); + + /* We have to create all optional fields as the default is not empty */ + pos= strmov(pos, " FIELDS TERMINATED BY "); pos= pretty_print_str(pos, sql_ex.field_term, sql_ex.field_term_len); if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG) pos= strmov(pos, " OPTIONALLY "); @@ -4101,7 +4118,7 @@ void Load_log_event::pack_info(Protocol *protocol) if (!(buf= (char*) my_malloc(get_query_buffer_length(), MYF(MY_WME)))) return; - print_query(TRUE, buf, &end, 0, 0); + print_query(TRUE, NULL, buf, &end, 0, 0); protocol->store(buf, end-buf, &my_charset_bin); my_free(buf, MYF(0)); } @@ -4366,9 +4383,9 @@ void Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info, my_b_printf(&cache, "INFILE '%-*s' ", fname_len, fname); if (sql_ex.opt_flags & REPLACE_FLAG) - my_b_printf(&cache," REPLACE "); + my_b_printf(&cache,"REPLACE "); else if (sql_ex.opt_flags & IGNORE_FLAG) - my_b_printf(&cache," IGNORE "); + my_b_printf(&cache,"IGNORE "); my_b_printf(&cache, "INTO TABLE `%s`", table_name); my_b_printf(&cache, " FIELDS TERMINATED BY "); @@ -4480,8 +4497,8 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, new_db.length= db_len; new_db.str= (char *) rpl_filter->get_rewrite_db(db, &new_db.length); thd->set_db(new_db.str, new_db.length); - DBUG_ASSERT(thd->query == 0); - thd->query_length= 0; // Should not be needed + DBUG_ASSERT(thd->query() == 0); + thd->set_query_inner(NULL, 0); // Should not be needed thd->is_slave_error= 0; clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); @@ -4576,8 +4593,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, goto error; } - print_query(FALSE, load_data_query, &end, (char **)&thd->lex->fname_start, - (char **)&thd->lex->fname_end); + print_query(FALSE, NULL, load_data_query, &end, NULL, NULL); *end= 0; thd->set_query(load_data_query, (uint) (end - load_data_query)); @@ -6734,7 +6750,7 @@ void Execute_load_query_log_event::print(FILE* file, my_b_printf(&cache, "\'"); if (dup_handling == LOAD_DUP_REPLACE) my_b_printf(&cache, " REPLACE"); - my_b_printf(&cache, " INTO "); + my_b_printf(&cache, " INTO"); my_b_write(&cache, (uchar*) query + fn_pos_end, q_len-fn_pos_end); my_b_printf(&cache, "\n%s\n", print_event_info->delimiter); } @@ -7497,6 +7513,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) thd->reset_current_stmt_binlog_row_based(); const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error); thd->is_slave_error= 1; + DBUG_RETURN(error); } /* This code would ideally be placed in do_update_pos() instead, but @@ -7525,6 +7542,14 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) const_cast<Relay_log_info*>(rli)->last_event_start_time= my_time(0); } + if (get_flags(STMT_END_F)) + if ((error= rows_event_stmt_cleanup(rli, thd))) + rli->report(ERROR_LEVEL, error, + "Error in %s event: commit of row events failed, " + "table `%s`.`%s`", + get_type_str(), m_table->s->db.str, + m_table->s->table_name.str); + DBUG_RETURN(error); } @@ -7623,33 +7648,19 @@ Rows_log_event::do_update_pos(Relay_log_info *rli) if (get_flags(STMT_END_F)) { - if ((error= rows_event_stmt_cleanup(rli, thd)) == 0) - { - /* - Indicate that a statement is finished. - Step the group log position if we are not in a transaction, - otherwise increase the event log position. - */ - rli->stmt_done(log_pos, when); - - /* - Clear any errors pushed in thd->net.last_err* if for example "no key - found" (as this is allowed). This is a safety measure; apparently - those errors (e.g. when executing a Delete_rows_log_event of a - non-existing row, like in rpl_row_mystery22.test, - thd->net.last_error = "Can't find record in 't1'" and last_errno=1032) - do not become visible. We still prefer to wipe them out. - */ - thd->clear_error(); - } - else - { - rli->report(ERROR_LEVEL, error, - "Error in %s event: commit of row events failed, " - "table `%s`.`%s`", - get_type_str(), m_table->s->db.str, - m_table->s->table_name.str); - } + /* + Indicate that a statement is finished. + Step the group log position if we are not in a transaction, + otherwise increase the event log position. + */ + rli->stmt_done(log_pos, when); + /* + Clear any errors in thd->net.last_err*. It is not known if this is + needed or not. It is believed that any errors that may exist in + thd->net.last_err* are allowed. Examples of errors are "key not + found", which is produced in the test case rpl_row_conflicts.test + */ + thd->clear_error(); } else { @@ -8314,6 +8325,16 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability /* Honor next number column if present */ m_table->next_number_field= m_table->found_next_number_field; + /* + * Fixed Bug#45999, In RBR, Store engine of Slave auto-generates new + * sequence numbers for auto_increment fields if the values of them are 0. + * If generateing a sequence number is decided by the values of + * table->auto_increment_field_not_null and SQL_MODE(if includes + * MODE_NO_AUTO_VALUE_ON_ZERO) in update_auto_increment function. + * SQL_MODE of slave sql thread is always consistency with master's. + * In RBR, auto_increment fields never are NULL. + */ + m_table->auto_increment_field_not_null= TRUE; return error; } @@ -8323,6 +8344,7 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability * { int local_error= 0; m_table->next_number_field=0; + m_table->auto_increment_field_not_null= FALSE; if (bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1 || m_table->s->db_type()->db_type == DB_TYPE_NDBCLUSTER) { @@ -8826,11 +8848,11 @@ int Rows_log_event::find_row(const Relay_log_info *rli) */ store_record(table,record[1]); - if (table->s->keys > 0) + if (table->s->keys > 0 && table->s->keys_in_use.is_set(0)) { DBUG_PRINT("info",("locating record using primary key (index_read)")); - /* We have a key: search the table using the index */ + /* The 0th key is active: search the table using the index */ if (!table->file->inited && (error= table->file->ha_index_init(0, FALSE))) { DBUG_PRINT("info",("ha_index_init returns error %d",error)); diff --git a/sql/log_event.h b/sql/log_event.h index 13ab4330415..3c59043aa53 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1960,15 +1960,15 @@ private: class Load_log_event: public Log_event { private: - uint get_query_buffer_length(); - void print_query(bool need_db, char *buf, char **end, - char **fn_start, char **fn_end); protected: int copy_log_event(const char *buf, ulong event_len, int body_offset, const Format_description_log_event* description_event); public: + uint get_query_buffer_length(); + void print_query(bool need_db, const char *cs, char *buf, char **end, + char **fn_start, char **fn_end); ulong thread_id; ulong slave_proxy_id; uint32 table_name_len; diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 6c3b368eccd..040b71b94e0 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1814,33 +1814,6 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) const_cast<Relay_log_info*>(rli)->last_event_start_time= my_time(0); } - DBUG_RETURN(0); -} - - -Log_event::enum_skip_reason -Old_rows_log_event::do_shall_skip(Relay_log_info *rli) -{ - /* - If the slave skip counter is 1 and this event does not end a - statement, then we should not start executing on the next event. - Otherwise, we defer the decision to the normal skipping logic. - */ - if (rli->slave_skip_counter == 1 && !get_flags(STMT_END_F)) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); -} - -int -Old_rows_log_event::do_update_pos(Relay_log_info *rli) -{ - DBUG_ENTER("Old_rows_log_event::do_update_pos"); - int error= 0; - - DBUG_PRINT("info", ("flags: %s", - get_flags(STMT_END_F) ? "STMT_END_F " : "")); - if (get_flags(STMT_END_F)) { /* @@ -1869,7 +1842,12 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli) are involved, commit the transaction and flush the pending event to the binlog. */ - error= ha_autocommit_or_rollback(thd, 0); + if ((error= ha_autocommit_or_rollback(thd, 0))) + rli->report(ERROR_LEVEL, error, + "Error in %s event: commit of row events failed, " + "table `%s`.`%s`", + get_type_str(), m_table->s->db.str, + m_table->s->table_name.str); /* Now what if this is not a transactional engine? we still need to @@ -1882,33 +1860,51 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli) */ thd->reset_current_stmt_binlog_row_based(); - rli->cleanup_context(thd, 0); - if (error == 0) - { - /* - Indicate that a statement is finished. - Step the group log position if we are not in a transaction, - otherwise increase the event log position. - */ - rli->stmt_done(log_pos, when); + const_cast<Relay_log_info*>(rli)->cleanup_context(thd, 0); + } - /* - Clear any errors pushed in thd->net.client_last_err* if for - example "no key found" (as this is allowed). This is a safety - measure; apparently those errors (e.g. when executing a - Delete_rows_log_event_old of a non-existing row, like in - rpl_row_mystery22.test, thd->net.last_error = "Can't - find record in 't1'" and last_errno=1032) do not become - visible. We still prefer to wipe them out. - */ - thd->clear_error(); - } - else - rli->report(ERROR_LEVEL, error, - "Error in %s event: commit of row events failed, " - "table `%s`.`%s`", - get_type_str(), m_table->s->db.str, - m_table->s->table_name.str); + DBUG_RETURN(error); +} + + +Log_event::enum_skip_reason +Old_rows_log_event::do_shall_skip(Relay_log_info *rli) +{ + /* + If the slave skip counter is 1 and this event does not end a + statement, then we should not start executing on the next event. + Otherwise, we defer the decision to the normal skipping logic. + */ + if (rli->slave_skip_counter == 1 && !get_flags(STMT_END_F)) + return Log_event::EVENT_SKIP_IGNORE; + else + return Log_event::do_shall_skip(rli); +} + +int +Old_rows_log_event::do_update_pos(Relay_log_info *rli) +{ + DBUG_ENTER("Old_rows_log_event::do_update_pos"); + int error= 0; + + DBUG_PRINT("info", ("flags: %s", + get_flags(STMT_END_F) ? "STMT_END_F " : "")); + + if (get_flags(STMT_END_F)) + { + /* + Indicate that a statement is finished. + Step the group log position if we are not in a transaction, + otherwise increase the event log position. + */ + rli->stmt_done(log_pos, when); + /* + Clear any errors in thd->net.last_err*. It is not known if this is + needed or not. It is believed that any errors that may exist in + thd->net.last_err* are allowed. Examples of errors are "key not + found", which is produced in the test case rpl_row_conflicts.test + */ + thd->clear_error(); } else { diff --git a/sql/my_decimal.h b/sql/my_decimal.h index d991dd1c54c..d736bad9a4b 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -48,12 +48,10 @@ C_MODE_END digits * number of decimal digits in one our big digit - number of decimal digits in one our big digit decreased by 1 (because we always put decimal point on the border of our big digits)) - - This value is 65 due to historical reasons partly due to it being used - as the maximum allowed precision and not the actual maximum precision. */ #define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2) #define DECIMAL_MAX_SCALE 30 +#define DECIMAL_NOT_SPECIFIED 31 /** maximum length of string representation (number of maximum decimal @@ -77,6 +75,12 @@ inline uint my_decimal_size(uint precision, uint scale) } +inline int my_decimal_int_part(uint precision, uint decimals) +{ + return precision - ((decimals == DECIMAL_NOT_SPECIFIED) ? 0 : decimals); +} + + /** my_decimal class limits 'decimal_t' type to what we need in MySQL. @@ -180,7 +184,7 @@ inline uint my_decimal_length_to_precision(uint length, uint scale, } inline uint32 my_decimal_precision_to_length_no_truncation(uint precision, - uint scale, + uint8 scale, bool unsigned_flag) { /* @@ -192,7 +196,7 @@ inline uint32 my_decimal_precision_to_length_no_truncation(uint precision, (unsigned_flag || !precision ? 0 : 1)); } -inline uint32 my_decimal_precision_to_length(uint precision, uint scale, +inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale, bool unsigned_flag) { /* diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d80681d337f..2af7654e381 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -2303,10 +2303,9 @@ enum enum_explain_filename_mode { EXPLAIN_ALL_VERBOSE= 0, EXPLAIN_PARTITIONS_VERBOSE, - EXPLAIN_PARTITIONS_AS_COMMENT, - EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING + EXPLAIN_PARTITIONS_AS_COMMENT }; -uint explain_filename(const char *from, char *to, uint to_length, +uint explain_filename(THD* thd, const char *from, char *to, uint to_length, enum_explain_filename_mode explain_mode); uint filename_to_tablename(const char *from, char *to, uint to_length); uint tablename_to_filename(const char *from, char *to, uint to_length); @@ -2460,6 +2459,7 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) table->tablenr= tablenr; table->map= (table_map) 1 << tablenr; table->force_index= table_list->force_index; + table->force_index_order= table->force_index_group= 0; table->covering_keys= table->s->keys_for_keyread; table->merge_keys.clear_all(); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 53b95527a91..1bd3b1c66d0 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -28,6 +28,7 @@ #include "mysys_err.h" #include "events.h" #include <waiting_threads.h> +#include "debug_sync.h" #include "../storage/myisam/ha_myisam.h" @@ -497,6 +498,9 @@ my_bool lower_case_file_system= 0; my_bool opt_large_pages= 0; my_bool opt_myisam_use_mmap= 0; uint opt_large_page_size= 0; +#if defined(ENABLED_DEBUG_SYNC) +uint opt_debug_sync_timeout= 0; +#endif /* defined(ENABLED_DEBUG_SYNC) */ my_bool opt_old_style_user_limits= 0, trust_function_creators= 0; /* True if there is at least one per-hour limit for some user, so we should @@ -1136,13 +1140,13 @@ void kill_mysql(void) #if defined(__NETWARE__) extern "C" void kill_server(int sig_ptr) -#define RETURN_FROM_KILL_SERVER DBUG_VOID_RETURN +#define RETURN_FROM_KILL_SERVER return #elif !defined(__WIN__) static void *kill_server(void *sig_ptr) -#define RETURN_FROM_KILL_SERVER DBUG_RETURN(0) +#define RETURN_FROM_KILL_SERVER return 0 #else static void __cdecl kill_server(int sig_ptr) -#define RETURN_FROM_KILL_SERVER DBUG_VOID_RETURN +#define RETURN_FROM_KILL_SERVER return #endif { DBUG_ENTER("kill_server"); @@ -1150,7 +1154,10 @@ static void __cdecl kill_server(int sig_ptr) int sig=(int) (long) sig_ptr; // This is passed a int // if there is a signal during the kill in progress, ignore the other if (kill_in_progress) // Safety + { + DBUG_LEAVE; RETURN_FROM_KILL_SERVER; + } kill_in_progress=TRUE; abort_loop=1; // This should be set if (sig != 0) // 0 is not a valid signal number @@ -1185,12 +1192,19 @@ static void __cdecl kill_server(int sig_ptr) pthread_join(select_thread, NULL); // wait for main thread #endif /* __NETWARE__ */ + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); pthread_exit(0); /* purecov: end */ -#endif /* EMBEDDED_LIBRARY */ + RETURN_FROM_KILL_SERVER; // Avoid compiler warnings + +#else /* EMBEDDED_LIBRARY*/ + + DBUG_LEAVE; RETURN_FROM_KILL_SERVER; + +#endif /* EMBEDDED_LIBRARY */ } @@ -1354,6 +1368,10 @@ void clean_up(bool print_message) #ifdef USE_REGEX my_regex_end(); #endif +#if defined(ENABLED_DEBUG_SYNC) + /* End the debug sync facility. See debug_sync.cc. */ + debug_sync_end(); +#endif /* defined(ENABLED_DEBUG_SYNC) */ #if !defined(EMBEDDED_LIBRARY) if (!opt_bootstrap) @@ -1777,7 +1795,7 @@ static void network_init(void) saPipeSecurity.lpSecurityDescriptor = &sdPipeDescriptor; saPipeSecurity.bInheritHandle = FALSE; if ((hPipe= CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX, + PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, @@ -2012,8 +2030,9 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache) my_thread_end(); (void) pthread_cond_broadcast(&COND_thread_count); + DBUG_LEAVE; // Must match DBUG_ENTER() pthread_exit(0); - DBUG_RETURN(0); // Impossible + return 0; // Avoid compiler warnings } @@ -2580,7 +2599,7 @@ terribly wrong...\n"); } fprintf(stderr, "Trying to get some variables.\n\ Some pointers may be invalid and cause the dump to abort...\n"); - my_safe_print_str("thd->query", thd->query, 1024); + my_safe_print_str("thd->query", thd->query(), 1024); fprintf(stderr, "thd->thread_id=%lu\n", (ulong) thd->thread_id); fprintf(stderr, "thd->killed=%s\n", kreason); } @@ -2837,7 +2856,9 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) DBUG_PRINT("quit",("signal_handler: calling my_thread_end()")); my_thread_end(); signal_thread_in_use= 0; + DBUG_LEAVE; // Must match DBUG_ENTER() pthread_exit(0); // Safety + return 0; // Avoid compiler warnings } switch (sig) { case SIGTERM: @@ -3557,6 +3578,12 @@ static int init_common_variables(const char *conf_file_name, int argc, sys_var_slow_log_path.value= my_strdup(s, MYF(0)); sys_var_slow_log_path.value_length= strlen(s); +#if defined(ENABLED_DEBUG_SYNC) + /* Initialize the debug sync facility. See debug_sync.cc. */ + if (debug_sync_init()) + return 1; /* purecov: tested */ +#endif /* defined(ENABLED_DEBUG_SYNC) */ + #if (ENABLE_TEMP_POOL) if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1)) return 1; @@ -4909,10 +4936,10 @@ static bool read_init_file(char *file_name) DBUG_ENTER("read_init_file"); DBUG_PRINT("enter",("name: %s",file_name)); if (!(file=my_fopen(file_name,O_RDONLY,MYF(MY_WME)))) - DBUG_RETURN(1); + DBUG_RETURN(TRUE); bootstrap(file); (void) my_fclose(file,MYF(MY_WME)); - DBUG_RETURN(0); + DBUG_RETURN(FALSE); } @@ -4966,7 +4993,7 @@ void create_thread_to_handle_connection(THD *thd) handle_one_connection, (void*) thd))) { - /* purify: begin inspected */ + /* purecov: begin inspected */ DBUG_PRINT("error", ("Can't create thread to handle request (error %d)", error)); @@ -5324,17 +5351,26 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused))) pthread_handler_t handle_connections_namedpipes(void *arg) { HANDLE hConnectedPipe; - BOOL fConnected; + OVERLAPPED connectOverlapped = {0}; THD *thd; my_thread_init(); DBUG_ENTER("handle_connections_namedpipes"); - (void) my_pthread_getprio(pthread_self()); // For debugging + connectOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); DBUG_PRINT("general",("Waiting for named pipe connections.")); while (!abort_loop) { /* wait for named pipe connection */ - fConnected = ConnectNamedPipe(hPipe, NULL); + BOOL fConnected= ConnectNamedPipe(hPipe, &connectOverlapped); + if (!fConnected && (GetLastError() == ERROR_IO_PENDING)) + { + /* + ERROR_IO_PENDING says async IO has started but not yet finished. + GetOverlappedResult will wait for completion. + */ + DWORD bytes; + fConnected= GetOverlappedResult(hPipe, &connectOverlapped,&bytes, TRUE); + } if (abort_loop) break; if (!fConnected) @@ -5343,7 +5379,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg) { CloseHandle(hPipe); if ((hPipe= CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX, + PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, @@ -5363,7 +5399,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg) hConnectedPipe = hPipe; /* create new pipe for new connection */ if ((hPipe = CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX, + PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, @@ -5385,7 +5421,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg) CloseHandle(hConnectedPipe); continue; } - if (!(thd->net.vio = vio_new_win32pipe(hConnectedPipe)) || + if (!(thd->net.vio= vio_new_win32pipe(hConnectedPipe)) || my_net_init(&thd->net, thd->net.vio)) { close_connection(thd, ER_OUT_OF_RESOURCES, 1); @@ -5396,7 +5432,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg) thd->security_ctx->host= my_strdup(my_localhost, MYF(0)); create_new_thread(thd); } - + CloseHandle(connectOverlapped.hEvent); decrement_handler_count(); DBUG_RETURN(0); } @@ -5573,8 +5609,7 @@ pthread_handler_t handle_connections_shared_memory(void *arg) errmsg= "Could not set client to read mode"; goto errorconn; } - if (!(thd->net.vio= vio_new_win32shared_memory(&thd->net, - handle_client_file_map, + if (!(thd->net.vio= vio_new_win32shared_memory(handle_client_file_map, handle_client_map, event_client_wrote, event_client_read, @@ -5814,6 +5849,9 @@ enum options_mysqld OPT_LOG_SLOW_SLAVE_STATEMENTS, OPT_DEBUG_CRC, OPT_DEBUG_ON, OPT_OLD_MODE, OPT_TEST_IGNORE_WRONG_OPTIONS, +#if defined(ENABLED_DEBUG_SYNC) + OPT_DEBUG_SYNC_TIMEOUT, +#endif /* defined(ENABLED_DEBUG_SYNC) */ OPT_SLAVE_EXEC_MODE, OPT_DEADLOCK_SEARCH_DEPTH_SHORT, OPT_DEADLOCK_SEARCH_DEPTH_LONG, @@ -6634,6 +6672,14 @@ log and this option does nothing anymore.", "Decision to use in heuristic recover process. Possible values are COMMIT or ROLLBACK.", (uchar**) &opt_tc_heuristic_recover, (uchar**) &opt_tc_heuristic_recover, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#if defined(ENABLED_DEBUG_SYNC) + {"debug-sync-timeout", OPT_DEBUG_SYNC_TIMEOUT, + "Enable the debug sync facility " + "and optionally specify a default wait timeout in seconds. " + "A zero value keeps the facility disabled.", + (uchar**) &opt_debug_sync_timeout, 0, + 0, GET_UINT, OPT_ARG, 0, 0, UINT_MAX, 0, 0, 0}, +#endif /* defined(ENABLED_DEBUG_SYNC) */ {"temp-pool", OPT_TEMP_POOL, #if (ENABLE_TEMP_POOL) "Using this option will cause most temporary files created to use a small set of names, rather than a unique name for each new file.", @@ -7846,6 +7892,9 @@ static int mysql_init_variables(void) bzero((uchar*) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list)); bzero((char *) &global_status_var, sizeof(global_status_var)); opt_large_pages= 0; +#if defined(ENABLED_DEBUG_SYNC) + opt_debug_sync_timeout= 0; +#endif /* defined(ENABLED_DEBUG_SYNC) */ key_map_full.set_all(); /* Character sets */ @@ -8658,6 +8707,22 @@ mysqld_get_one_option(int optid, /* Used for testing options */ opt_ignore_wrong_options= 1; break; +#if defined(ENABLED_DEBUG_SYNC) + case OPT_DEBUG_SYNC_TIMEOUT: + /* + Debug Sync Facility. See debug_sync.cc. + Default timeout for WAIT_FOR action. + Default value is zero (facility disabled). + If option is given without an argument, supply a non-zero value. + */ + if (!argument) + { + /* purecov: begin tested */ + opt_debug_sync_timeout= DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT; + /* purecov: end */ + } + break; +#endif /* defined(ENABLED_DEBUG_SYNC) */ } return 0; } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 9c0929671a1..cff1b89179d 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5710,6 +5710,27 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, !(conf_func->compare_collation()->state & MY_CS_BINSORT)) goto end; + if (key_part->image_type == Field::itMBR) + { + switch (type) { + case Item_func::SP_EQUALS_FUNC: + case Item_func::SP_DISJOINT_FUNC: + case Item_func::SP_INTERSECTS_FUNC: + case Item_func::SP_TOUCHES_FUNC: + case Item_func::SP_CROSSES_FUNC: + case Item_func::SP_WITHIN_FUNC: + case Item_func::SP_CONTAINS_FUNC: + case Item_func::SP_OVERLAPS_FUNC: + break; + default: + /* + We cannot involve spatial indexes for queries that + don't use MBREQUALS(), MBRDISJOINT(), etc. functions. + */ + goto end; + } + } + if (param->using_real_indexes) optimize_range= field->optimize_range(param->real_keynr[key_part->key], key_part->part); @@ -5877,6 +5898,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, if (type == Item_func::LT_FUNC && (value->val_int() > 0)) type = Item_func::LE_FUNC; else if (type == Item_func::GT_FUNC && + (field->type() != FIELD_TYPE_BIT) && !((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag && (value->val_int() < 0)) @@ -5891,6 +5913,17 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, goto end; } field->table->in_use->variables.sql_mode= orig_sql_mode; + + /* + Any sargable predicate except "<=>" involving NULL as a constant is always + FALSE + */ + if (type != Item_func::EQUAL_FUNC && field->is_real_null()) + { + tree= &null_element; + goto end; + } + str= (uchar*) alloc_root(alloc, key_part->store_length+1); if (!str) goto end; @@ -5914,7 +5947,9 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, */ if (field->result_type() == INT_RESULT && value->result_type() == INT_RESULT && - ((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag) + ((field->type() == FIELD_TYPE_BIT || + ((Field_num *) field)->unsigned_flag) && + !((Item_int*) value)->unsigned_flag)) { longlong item_val= value->val_int(); if (item_val < 0) @@ -5934,7 +5969,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, switch (type) { case Item_func::LT_FUNC: - if (stored_field_cmp_to_item(field,value) == 0) + if (stored_field_cmp_to_item(param->thd, field, value) == 0) tree->max_flag=NEAR_MAX; /* fall through */ case Item_func::LE_FUNC: @@ -5949,14 +5984,14 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, case Item_func::GT_FUNC: /* Don't use open ranges for partial key_segments */ if ((!(key_part->flag & HA_PART_KEY_SEG)) && - (stored_field_cmp_to_item(field, value) <= 0)) + (stored_field_cmp_to_item(param->thd, field, value) <= 0)) tree->min_flag=NEAR_MIN; tree->max_flag= NO_MAX_RANGE; break; case Item_func::GE_FUNC: /* Don't use open ranges for partial key_segments */ if ((!(key_part->flag & HA_PART_KEY_SEG)) && - (stored_field_cmp_to_item(field,value) < 0)) + (stored_field_cmp_to_item(param->thd, field, value) < 0)) tree->min_flag= NEAR_MIN; tree->max_flag=NO_MAX_RANGE; break; @@ -6510,6 +6545,63 @@ get_range(SEL_ARG **e1,SEL_ARG **e2,SEL_ARG *root1) } +/** + Combine two range expression under a common OR. On a logical level, the + transformation is key_or( expr1, expr2 ) => expr1 OR expr2. + + Both expressions are assumed to be in the SEL_ARG format. In a logic sense, + theformat is reminiscent of DNF, since an expression such as the following + + ( 1 < kp1 < 10 AND p1 ) OR ( 10 <= kp2 < 20 AND p2 ) + + where there is a key consisting of keyparts ( kp1, kp2, ..., kpn ) and p1 + and p2 are valid SEL_ARG expressions over keyparts kp2 ... kpn, is a valid + SEL_ARG condition. The disjuncts appear ordered by the minimum endpoint of + the first range and ranges must not overlap. It follows that they are also + ordered by maximum endpoints. Thus + + ( 1 < kp1 <= 2 AND ( kp2 = 2 OR kp2 = 3 ) ) OR kp1 = 3 + + Is a a valid SER_ARG expression for a key of at least 2 keyparts. + + For simplicity, we will assume that expr2 is a single range predicate, + i.e. on the form ( a < x < b AND ... ). It is easy to generalize to a + disjunction of several predicates by subsequently call key_or for each + disjunct. + + The algorithm iterates over each disjunct of expr1, and for each disjunct + where the first keypart's range overlaps with the first keypart's range in + expr2: + + If the predicates are equal for the rest of the keyparts, or if there are + no more, the range in expr2 has its endpoints copied in, and the SEL_ARG + node in expr2 is deallocated. If more ranges became connected in expr1, the + surplus is also dealocated. If they differ, two ranges are created. + + - The range leading up to the overlap. Empty if endpoints are equal. + + - The overlapping sub-range. May be the entire range if they are equal. + + Finally, there may be one more range if expr2's first keypart's range has a + greater maximum endpoint than the last range in expr1. + + For the overlapping sub-range, we recursively call key_or. Thus in order to + compute key_or of + + (1) ( 1 < kp1 < 10 AND 1 < kp2 < 10 ) + + (2) ( 2 < kp1 < 20 AND 4 < kp2 < 20 ) + + We create the ranges 1 < kp <= 2, 2 < kp1 < 10, 10 <= kp1 < 20. For the + first one, we simply hook on the condition for the second keypart from (1) + : 1 < kp2 < 10. For the second range 2 < kp1 < 10, key_or( 1 < kp2 < 10, 4 + < kp2 < 20 ) is called, yielding 1 < kp2 < 20. For the last range, we reuse + the range 4 < kp2 < 20 from (2) for the second keypart. The result is thus + + ( 1 < kp1 <= 2 AND 1 < kp2 < 10 ) OR + ( 2 < kp1 < 10 AND 1 < kp2 < 20 ) OR + ( 10 <= kp1 < 20 AND 4 < kp2 < 20 ) +*/ static SEL_ARG * key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) { @@ -6661,7 +6753,21 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) key1=key1->tree_delete(save); } last->copy_min(tmp); - if (last->copy_min(key2) || last->copy_max(key2)) + bool full_range= last->copy_min(key2); + if (!full_range) + { + if (last->next && key2->cmp_max_to_min(last->next) >= 0) + { + last->max_value= last->next->min_value; + if (last->next->min_flag & NEAR_MIN) + last->max_flag&= ~NEAR_MAX; + else + last->max_flag|= NEAR_MAX; + } + else + full_range= last->copy_max(key2); + } + if (full_range) { // Full range key1->free_tree(); for (; key2 ; key2=key2->next) @@ -6671,8 +6777,6 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2) return 0; } } - key2=key2->next; - continue; } if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0) diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index f03915bf38f..87ef3af6e44 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -97,7 +97,8 @@ static ulonglong get_exact_record_count(TABLE_LIST *tables) @note This function is only called for queries with sum functions and no - GROUP BY part. + GROUP BY part. This means that the result set shall contain a single + row only @retval 0 no errors diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 8fc9e584789..e7d3e842903 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -483,10 +483,8 @@ static bool check_engine_condition(partition_element *p_elem, { DBUG_RETURN(TRUE); } - else - { - DBUG_RETURN(FALSE); - } + + DBUG_RETURN(FALSE); } diff --git a/sql/records.cc b/sql/records.cc index 8bab6fd46a4..2fc5a26a210 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -57,10 +57,12 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, { empty_record(table); bzero((char*) info,sizeof(*info)); + info->thd= thd; info->table= table; info->file= table->file; info->record= table->record[0]; info->print_error= print_error; + info->unlock_row= rr_unlock_row; table->status=0; /* And it's always found */ if (!table->file->inited) @@ -186,6 +188,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, } info->select=select; info->print_error=print_error; + info->unlock_row= rr_unlock_row; info->ignore_not_found_rows= 0; table->status=0; /* And it's always found */ @@ -292,6 +295,12 @@ void end_read_record(READ_RECORD *info) static int rr_handle_error(READ_RECORD *info, int error) { + if (info->thd->killed) + { + info->thd->send_kill_message(); + return 1; + } + if (error == HA_ERR_END_OF_FILE) error= -1; else @@ -312,12 +321,7 @@ static int rr_quick(READ_RECORD *info) int tmp; while ((tmp= info->select->quick->get_next())) { - if (info->thd->killed) - { - my_error(ER_SERVER_SHUTDOWN, MYF(0)); - return 1; - } - if (tmp != HA_ERR_RECORD_DELETED) + if (info->thd->killed || (tmp != HA_ERR_RECORD_DELETED)) { tmp= rr_handle_error(info, tmp); break; @@ -380,16 +384,11 @@ int rr_sequential(READ_RECORD *info) int tmp; while ((tmp=info->file->rnd_next(info->record))) { - if (info->thd->killed) - { - info->thd->send_kill_message(); - return 1; - } /* rnd_next can return RECORD_DELETED for MyISAM when one thread is reading and another deleting without locks. */ - if (tmp != HA_ERR_RECORD_DELETED) + if (info->thd->killed || (tmp != HA_ERR_RECORD_DELETED)) { tmp= rr_handle_error(info, tmp); break; diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 582348608de..312499bb4ee 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -638,9 +638,11 @@ err: if (recovery_captain) mysql_close(recovery_captain); delete thd; + + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); pthread_exit(0); - DBUG_RETURN(0); + return 0; // Avoid compiler warnings } #endif diff --git a/sql/rpl_filter.cc b/sql/rpl_filter.cc index 68272c58bb1..ee3fc358b60 100644 --- a/sql/rpl_filter.cc +++ b/sql/rpl_filter.cc @@ -155,8 +155,10 @@ Rpl_filter::db_ok(const char* db) and db was not selected, do not replicate. */ if (!db) + { + DBUG_PRINT("exit", ("Don't replicate")); DBUG_RETURN(0); - + } if (!do_db.is_empty()) // if the do's are not empty { I_List_iterator<i_string> it(do_db); @@ -167,6 +169,7 @@ Rpl_filter::db_ok(const char* db) if (!strcmp(tmp->ptr, db)) DBUG_RETURN(1); // match } + DBUG_PRINT("exit", ("Don't replicate")); DBUG_RETURN(0); } else // there are some elements in the don't, otherwise we cannot get here @@ -177,7 +180,10 @@ Rpl_filter::db_ok(const char* db) while ((tmp=it++)) { if (!strcmp(tmp->ptr, db)) + { + DBUG_PRINT("exit", ("Don't replicate")); DBUG_RETURN(0); // match + } } DBUG_RETURN(1); } diff --git a/sql/set_var.cc b/sql/set_var.cc index 9fe9982858f..166f280be4e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -553,11 +553,11 @@ static sys_var_const sys_skip_networking(&vars, "skip_networking", static sys_var_const sys_skip_show_database(&vars, "skip_show_database", OPT_GLOBAL, SHOW_BOOL, (uchar*) &opt_skip_show_db); -#ifdef HAVE_SYS_UN_H + static sys_var_const sys_socket(&vars, "socket", OPT_GLOBAL, SHOW_CHAR_PTR, (uchar*) &mysqld_unix_port); -#endif + #ifdef HAVE_THR_SETCONCURRENCY /* purecov: begin tested */ static sys_var_const sys_thread_concurrency(&vars, "thread_concurrency", @@ -649,6 +649,12 @@ static sys_var_long_ptr sys_table_cache_size(&vars, "table_open_cache", &table_cache_size); static sys_var_long_ptr sys_table_lock_wait_timeout(&vars, "table_lock_wait_timeout", &table_lock_wait_timeout); + +#if defined(ENABLED_DEBUG_SYNC) +/* Debug Sync Facility. Implemented in debug_sync.cc. */ +static sys_var_debug_sync sys_debug_sync(&vars, "debug_sync"); +#endif /* defined(ENABLED_DEBUG_SYNC) */ + static sys_var_long_ptr sys_thread_cache_size(&vars, "thread_cache_size", &thread_cache_size); #if HAVE_POOL_OF_THREADS == 1 @@ -3446,8 +3452,7 @@ int set_var_init() uint count= 0; DBUG_ENTER("set_var_init"); - for (sys_var *var=vars.first; var; var= var->next, count++) - ; + for (sys_var *var=vars.first; var; var= var->next, count++) ; if (hash_init(&system_variable_hash, system_charset_info, count, 0, 0, (hash_get_key) get_sys_var_length, 0, HASH_UNIQUE)) @@ -4255,6 +4260,7 @@ end_with_read_lock: } +#ifndef DBUG_OFF /* even session variable here requires SUPER, because of -#o,file */ bool sys_var_thd_dbug::check(THD *thd, set_var *var) { @@ -4302,6 +4308,8 @@ uchar *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b) } return (uchar*) thd->strdup(buf); } +#endif /* DBUG_OFF */ + #ifdef HAVE_EVENT_SCHEDULER bool sys_var_event_scheduler::check(THD *thd, set_var *var) diff --git a/sql/set_var.h b/sql/set_var.h index f2c7c0ba30f..5b4760589af 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -634,6 +634,7 @@ public: uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; +#ifndef DBUG_OFF class sys_var_thd_dbug :public sys_var_thd { public: @@ -647,8 +648,23 @@ public: void set_default(THD *thd, enum_var_type type) { DBUG_POP(); } uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *b); }; +#endif /* DBUG_OFF */ - +#if defined(ENABLED_DEBUG_SYNC) +/* Debug Sync Facility. Implemented in debug_sync.cc. */ +class sys_var_debug_sync :public sys_var_thd +{ +public: + sys_var_debug_sync(sys_var_chain *chain, const char *name_arg) + :sys_var_thd(name_arg) + { chain_sys_var(chain); } + bool check(THD *thd, set_var *var); + bool update(THD *thd, set_var *var); + SHOW_TYPE show_type() { return SHOW_CHAR; } + bool check_update_type(Item_result type) { return type != STRING_RESULT; } + uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); +}; +#endif /* defined(ENABLED_DEBUG_SYNC) */ /* some variables that require special handling */ diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index b0ed27b9977..20f51a952bc 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -4702,7 +4702,7 @@ ER_NOT_SUPPORTED_YET 42000 swe "Denna version av MySQL kan ännu inte utföra '%s'" ER_MASTER_FATAL_ERROR_READING_BINLOG nla "Kreeg fatale fout %d: '%-.128s' van master tijdens lezen van data uit binaire log" - eng "Got fatal error %d: '%-.128s' from master when reading data from binary log" + eng "Got fatal error %d from master when reading data from binary log: '%-.128s'" ger "Schwerer Fehler %d: '%-.128s vom Master beim Lesen des binären Logs" ita "Errore fatale %d: '%-.128s' dal master leggendo i dati dal log binario" por "Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log" @@ -6206,3 +6206,10 @@ ER_TOO_MANY_CONCURRENT_TRXS WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED eng "Non-ASCII separator arguments are not fully supported" + +ER_DEBUG_SYNC_TIMEOUT + eng "debug sync point wait timed out" + ger "Debug Sync Point Wartezeit überschritten" +ER_DEBUG_SYNC_HIT_LIMIT + eng "debug sync point hit limit reached" + ger "Debug Sync Point Hit Limit erreicht" diff --git a/sql/slave.cc b/sql/slave.cc index 1595c5372cc..94e20b594fb 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1238,7 +1238,8 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, thd->db = (char*)db; DBUG_ASSERT(thd->db != 0); thd->db_length= strlen(thd->db); - mysql_parse(thd, thd->query, packet_len, &found_semicolon); // run create table + /* run create table */ + mysql_parse(thd, thd->query(), packet_len, &found_semicolon); thd->db = save_db; // leave things the way the were before thd->db_length= save_db_length; thd->options = save_options; @@ -2033,8 +2034,7 @@ static int has_temporary_error(THD *thd) @retval 2 No error calling ev->apply_event(), but error calling ev->update_pos(). */ -int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, - bool skip) +int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli) { int exec_res= 0; @@ -2079,37 +2079,33 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, ev->when= my_time(0); ev->thd = thd; // because up to this point, ev->thd == 0 - if (skip) - { - int reason= ev->shall_skip(rli); - if (reason == Log_event::EVENT_SKIP_COUNT) - --rli->slave_skip_counter; - pthread_mutex_unlock(&rli->data_lock); - if (reason == Log_event::EVENT_SKIP_NOT) - exec_res= ev->apply_event(rli); + int reason= ev->shall_skip(rli); + if (reason == Log_event::EVENT_SKIP_COUNT) + --rli->slave_skip_counter; + pthread_mutex_unlock(&rli->data_lock); + if (reason == Log_event::EVENT_SKIP_NOT) + exec_res= ev->apply_event(rli); + #ifndef DBUG_OFF - /* - This only prints information to the debug trace. + /* + This only prints information to the debug trace. - TODO: Print an informational message to the error log? - */ - static const char *const explain[] = { - // EVENT_SKIP_NOT, - "not skipped", - // EVENT_SKIP_IGNORE, - "skipped because event should be ignored", - // EVENT_SKIP_COUNT - "skipped because event skip counter was non-zero" - }; - DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d", - thd->options & OPTION_BEGIN ? 1 : 0, - rli->get_flag(Relay_log_info::IN_STMT))); - DBUG_PRINT("skip_event", ("%s event was %s", - ev->get_type_str(), explain[reason])); + TODO: Print an informational message to the error log? + */ + static const char *const explain[] = { + // EVENT_SKIP_NOT, + "not skipped", + // EVENT_SKIP_IGNORE, + "skipped because event should be ignored", + // EVENT_SKIP_COUNT + "skipped because event skip counter was non-zero" + }; + DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d", + thd->options & OPTION_BEGIN ? 1 : 0, + rli->get_flag(Relay_log_info::IN_STMT))); + DBUG_PRINT("skip_event", ("%s event was %s", + ev->get_type_str(), explain[reason])); #endif - } - else - exec_res= ev->apply_event(rli); DBUG_PRINT("info", ("apply_event error = %d", exec_res)); if (exec_res == 0) @@ -2229,7 +2225,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) delete ev; DBUG_RETURN(1); } - exec_res= apply_event_and_update_pos(ev, thd, rli, TRUE); + exec_res= apply_event_and_update_pos(ev, thd, rli); /* Format_description_log_event should not be deleted because it will be @@ -2629,15 +2625,19 @@ Log entry on master is longer than max_allowed_packet (%ld) on \ slave. If the entry is correct, restart the server with a higher value of \ max_allowed_packet", thd->variables.max_allowed_packet); + mi->report(ERROR_LEVEL, ER_NET_PACKET_TOO_LARGE, + "%s", ER(ER_NET_PACKET_TOO_LARGE)); goto err; case ER_MASTER_FATAL_ERROR_READING_BINLOG: - sql_print_error(ER(mysql_error_number), mysql_error_number, - mysql_error(mysql)); + mi->report(ERROR_LEVEL, ER_MASTER_FATAL_ERROR_READING_BINLOG, + ER(ER_MASTER_FATAL_ERROR_READING_BINLOG), + mysql_error_number, mysql_error(mysql)); goto err; - case EE_OUTOFMEMORY: - case ER_OUTOFMEMORY: + case ER_OUT_OF_RESOURCES: sql_print_error("\ Stopping slave I/O thread due to out-of-memory error from master"); + mi->report(ERROR_LEVEL, ER_OUT_OF_RESOURCES, + "%s", ER(ER_OUT_OF_RESOURCES)); goto err; } if (try_to_reconnect(thd, mysql, mi, &retry_count, suppress_warnings, @@ -2746,9 +2746,11 @@ err: pthread_cond_broadcast(&mi->stop_cond); // tell the world we are done DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5);); pthread_mutex_unlock(&mi->run_lock); + + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); pthread_exit(0); - DBUG_RETURN(0); // Can't return anything here + return 0; // Avoid compiler warnings } /* @@ -3104,10 +3106,11 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ pthread_cond_broadcast(&rli->stop_cond); DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5);); pthread_mutex_unlock(&rli->run_lock); // tell the world we are done - + + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); pthread_exit(0); - DBUG_RETURN(0); // Can't return anything here + return 0; // Avoid compiler warnings } @@ -3705,7 +3708,7 @@ extern "C" void slave_io_thread_detach_vio() { #ifdef SIGNAL_WITH_VIO_CLOSE THD *thd= current_thd; - if (thd->slave_thread) + if (thd && thd->slave_thread) thd->clear_active_vio(); #endif } diff --git a/sql/slave.h b/sql/slave.h index fe9694c2392..1a1cfcebd9b 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -191,8 +191,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, void set_slave_thread_options(THD* thd); void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli); void rotate_relay_log(Master_info* mi); -int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, - bool skip); +int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli); pthread_handler_t handle_slave_io(void *arg); pthread_handler_t handle_slave_sql(void *arg); diff --git a/sql/sp.cc b/sql/sp.cc index 4d840f53e2f..fd420732628 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -997,7 +997,7 @@ sp_drop_routine(THD *thd, int type, sp_name *name) if (ret == SP_OK) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); sp_cache_invalidate(); } @@ -1067,7 +1067,7 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) if (ret == SP_OK) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); sp_cache_invalidate(); } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index e7310787a35..f8cf85812d0 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -334,16 +334,18 @@ bool sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) { Item *expr_item; + enum_check_fields save_count_cuted_fields= thd->count_cuted_fields; + bool save_abort_on_warning= thd->abort_on_warning; + bool save_stmt_modified_non_trans_table= + thd->transaction.stmt.modified_non_trans_table; DBUG_ENTER("sp_eval_expr"); if (!*expr_item_ptr) - DBUG_RETURN(TRUE); + goto error; if (!(expr_item= sp_prepare_func_item(thd, expr_item_ptr))) - DBUG_RETURN(TRUE); - - bool err_status= FALSE; + goto error; /* Set THD flags to emit warnings/errors in case of overflow/type errors @@ -352,10 +354,6 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) Save original values and restore them after save. */ - enum_check_fields save_count_cuted_fields= thd->count_cuted_fields; - bool save_abort_on_warning= thd->abort_on_warning; - bool save_stmt_modified_non_trans_table= thd->transaction.stmt.modified_non_trans_table; - thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; thd->abort_on_warning= thd->variables.sql_mode & @@ -370,13 +368,18 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) thd->abort_on_warning= save_abort_on_warning; thd->transaction.stmt.modified_non_trans_table= save_stmt_modified_non_trans_table; - if (thd->is_error()) - { - /* Return error status if something went wrong. */ - err_status= TRUE; - } + if (!thd->is_error()) + DBUG_RETURN(FALSE); - DBUG_RETURN(err_status); +error: + /* + In case of error during evaluation, leave the result field set to NULL. + Sic: we can't do it in the beginning of the function because the + result field might be needed for its own re-evaluation, e.g. case of + set x = x + 1; + */ + result_field->set_null(); + DBUG_RETURN (TRUE); } @@ -2824,8 +2827,8 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) DBUG_ENTER("sp_instr_stmt::execute"); DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command())); - query= thd->query; - query_length= thd->query_length; + query= thd->query(); + query_length= thd->query_length(); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) /* This s-p instr is profilable and will be captured. */ thd->profiling.set_query_source(m_query.str, m_query.length); @@ -2838,10 +2841,11 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) queries with SP vars can't be cached) */ if (unlikely((thd->options & OPTION_LOG_OFF)==0)) - general_log_write(thd, COM_QUERY, thd->query, thd->query_length); + general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); if (query_cache_send_result_to_client(thd, - thd->query, thd->query_length) <= 0) + thd->query(), + thd->query_length()) <= 0) { res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 07b00d186b5..9d4eb362fe7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -263,8 +263,7 @@ my_bool acl_init(bool dont_read_acl_tables) acl_cache= new hash_filo(ACL_CACHE_SIZE, 0, 0, (hash_get_key) acl_entry_get_key, (hash_free_key) free, - lower_case_file_system ? - system_charset_info : &my_charset_bin); + &my_charset_utf8_bin); if (dont_read_acl_tables) { DBUG_RETURN(0); /* purecov: tested */ @@ -2252,10 +2251,13 @@ public: ulong sort; size_t key_length; GRANT_NAME(const char *h, const char *d,const char *u, - const char *t, ulong p); - GRANT_NAME (TABLE *form); + const char *t, ulong p, bool is_routine); + GRANT_NAME (TABLE *form, bool is_routine); virtual ~GRANT_NAME() {}; virtual bool ok() { return privs != 0; } + void set_user_details(const char *h, const char *d, + const char *u, const char *t, + bool is_routine); }; @@ -2273,38 +2275,48 @@ public: }; - -GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u, - const char *t, ulong p) - :privs(p) +void GRANT_NAME::set_user_details(const char *h, const char *d, + const char *u, const char *t, + bool is_routine) { /* Host given by user */ update_hostname(&host, strdup_root(&memex, h)); - db = strdup_root(&memex,d); + if (db != d) + { + db= strdup_root(&memex, d); + if (lower_case_table_names) + my_casedn_str(files_charset_info, db); + } user = strdup_root(&memex,u); sort= get_sort(3,host.hostname,db,user); - tname= strdup_root(&memex,t); - if (lower_case_table_names) + if (tname != t) { - my_casedn_str(files_charset_info, db); - my_casedn_str(files_charset_info, tname); + tname= strdup_root(&memex, t); + if (lower_case_table_names || is_routine) + my_casedn_str(files_charset_info, tname); } key_length= strlen(d) + strlen(u)+ strlen(t)+3; hash_key= (char*) alloc_root(&memex,key_length); strmov(strmov(strmov(hash_key,user)+1,db)+1,tname); } +GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u, + const char *t, ulong p, bool is_routine) + :db(0), tname(0), privs(p) +{ + set_user_details(h, d, u, t, is_routine); +} GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u, const char *t, ulong p, ulong c) - :GRANT_NAME(h,d,u,t,p), cols(c) + :GRANT_NAME(h,d,u,t,p, FALSE), cols(c) { (void) hash_init2(&hash_columns,4,system_charset_info, 0,0,0, (hash_get_key) get_key_column,0,0); } -GRANT_NAME::GRANT_NAME(TABLE *form) +GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine) { update_hostname(&host, get_field(&memex, form->field[0])); db= get_field(&memex,form->field[1]); @@ -2322,6 +2334,9 @@ GRANT_NAME::GRANT_NAME(TABLE *form) if (lower_case_table_names) { my_casedn_str(files_charset_info, db); + } + if (lower_case_table_names || is_routine) + { my_casedn_str(files_charset_info, tname); } key_length= (strlen(db) + strlen(user) + strlen(tname) + 3); @@ -2333,7 +2348,7 @@ GRANT_NAME::GRANT_NAME(TABLE *form) GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) - :GRANT_NAME(form) + :GRANT_NAME(form, FALSE) { uchar key[MAX_KEY_LENGTH]; @@ -3185,7 +3200,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, if (!result) /* success */ { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } rw_unlock(&LOCK_grant); @@ -3328,7 +3343,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, } grant_name= new GRANT_NAME(Str->host.str, db_name, Str->user.str, table_name, - rights); + rights, TRUE); if (!grant_name) { result= TRUE; @@ -3350,7 +3365,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, if (write_to_binlog) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } rw_unlock(&LOCK_grant); @@ -3462,7 +3477,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, if (!result) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } rw_unlock(&LOCK_grant); @@ -3539,10 +3554,10 @@ static my_bool grant_load_procs_priv(TABLE *p_table) MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC); DBUG_ENTER("grant_load_procs_priv"); - (void) hash_init(&proc_priv_hash,system_charset_info, + (void) hash_init(&proc_priv_hash, &my_charset_utf8_bin, 0,0,0, (hash_get_key) get_grant_table, 0,0); - (void) hash_init(&func_priv_hash,system_charset_info, + (void) hash_init(&func_priv_hash, &my_charset_utf8_bin, 0,0,0, (hash_get_key) get_grant_table, 0,0); p_table->file->ha_index_init(0, 1); @@ -3556,7 +3571,7 @@ static my_bool grant_load_procs_priv(TABLE *p_table) { GRANT_NAME *mem_check; HASH *hash; - if (!(mem_check=new (memex_ptr) GRANT_NAME(p_table))) + if (!(mem_check=new (memex_ptr) GRANT_NAME(p_table, TRUE))) { /* This could only happen if we are out memory */ goto end_unlock; @@ -3640,7 +3655,7 @@ static my_bool grant_load(THD *thd, TABLE_LIST *tables) thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; - (void) hash_init(&column_priv_hash,system_charset_info, + (void) hash_init(&column_priv_hash, &my_charset_utf8_bin, 0,0,0, (hash_get_key) get_grant_table, (hash_free_key) free_grant_table,0); @@ -4073,8 +4088,7 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref, db_name= table_ref->view_db.str; table_name= table_ref->view_name.str; if (table_ref->belong_to_view && - (thd->lex->sql_command == SQLCOM_SHOW_FIELDS || - thd->lex->sql_command == SQLCOM_SHOW_CREATE)) + thd->lex->sql_command == SQLCOM_SHOW_FIELDS) { view_privs= get_column_grant(thd, grant, db_name, table_name, name); if (view_privs & VIEW_ANY_ACL) @@ -5438,9 +5452,21 @@ static int handle_grant_struct(uint struct_no, bool drop, case 2: case 3: - grant_name->user= strdup_root(&mem, user_to->user.str); - update_hostname(&grant_name->host, - strdup_root(&mem, user_to->host.str)); + /* + Update the grant structure with the new user name and + host name + */ + grant_name->set_user_details(user_to->host.str, grant_name->db, + user_to->user.str, grant_name->tname, + TRUE); + + /* + Since username is part of the hash key, when the user name + is renamed, the hash key is changed. Update the hash to + ensure that the position matches the new hash key value + */ + hash_update(&column_priv_hash, (uchar*) grant_name, + (uchar*) grant_name->hash_key, grant_name->key_length); break; } } @@ -5663,7 +5689,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe()); if (some_users_created) - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -5736,7 +5762,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe()); if (some_users_deleted) - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -5821,7 +5847,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe()); if (some_users_renamed && mysql_bin_log.is_open()) - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -6003,7 +6029,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) VOID(pthread_mutex_unlock(&acl_cache->lock)); - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -6117,7 +6143,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, for (counter= 0, revoked= 0 ; counter < hash->records ; ) { GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter); - if (!my_strcasecmp(system_charset_info, grant_proc->db, sp_db) && + if (!my_strcasecmp(&my_charset_utf8_bin, grant_proc->db, sp_db) && !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name)) { LEX_USER lex_user; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 9fd47a655e0..0664a480aa9 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -17,6 +17,7 @@ /* Basic functions needed by many modules */ #include "mysql_priv.h" +#include "debug_sync.h" #include "sql_select.h" #include "sp_head.h" #include "sp.h" @@ -24,6 +25,7 @@ #include <m_ctype.h> #include <my_dir.h> #include <hash.h> +#include "rpl_filter.h" #ifdef __WIN__ #include <io.h> #endif @@ -106,7 +108,7 @@ static bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias, static void close_old_data_files(THD *thd, TABLE *table, bool morph_locks, bool send_refresh); static bool -has_two_write_locked_tables_with_auto_increment(TABLE_LIST *tables); +has_write_table_with_auto_increment(TABLE_LIST *tables); extern "C" uchar *table_cache_key(const uchar *record, size_t *length, @@ -950,6 +952,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock, close_old_data_files(thd,thd->open_tables,1,1); mysql_ha_flush(thd); + DEBUG_SYNC(thd, "after_flush_unlock"); bool found=1; /* Wait until all threads has closed all the tables we had locked */ @@ -1545,6 +1548,7 @@ void close_temporary_tables(THD *thd) s_query.length() - 1 /* to remove trailing ',' */, 0, FALSE, 0); qinfo.db= db.ptr(); + qinfo.db_len= db.length(); thd->variables.character_set_client= cs_save; mysql_bin_log.write(&qinfo); thd->variables.pseudo_thread_id= save_pseudo_thread_id; @@ -2306,7 +2310,8 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in) table->tablenr=thd->current_tablenr++; table->used_fields=0; table->const_table=0; - table->null_row= table->maybe_null= table->force_index= 0; + table->null_row= table->maybe_null= 0; + table->force_index= table->force_index_order= table->force_index_group= 0; table->status=STATUS_NO_RECORD; DBUG_RETURN(FALSE); } @@ -2964,7 +2969,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->tablenr=thd->current_tablenr++; table->used_fields=0; table->const_table=0; - table->null_row= table->maybe_null= table->force_index= 0; + table->null_row= table->maybe_null= 0; + table->force_index= table->force_index_order= table->force_index_group= 0; table->status=STATUS_NO_RECORD; table->insert_values= 0; table->fulltext_searched= 0; @@ -5112,7 +5118,16 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table) int decide_logging_format(THD *thd, TABLE_LIST *tables) { - if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG)) + /* + In SBR mode, we are only proceeding if we are binlogging this + statement, ie, the filtering rules won't later filter this out. + + This check here is needed to prevent some spurious error to be + raised in some cases (See BUG#42829). + */ + if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG) && + (thd->variables.binlog_format != BINLOG_FORMAT_STMT || + binlog_filter->db_ok(thd->db))) { /* Compute the starting vectors for the computations by creating a @@ -5295,18 +5310,22 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) thd->in_lock_tables=1; thd->options|= OPTION_TABLE_LOCK; /* - If we have >= 2 different tables to update with auto_inc columns, - statement-based binlogging won't work. We can solve this problem in - mixed mode by switching to row-based binlogging: + A query that modifies autoinc column in sub-statement can make the + master and slave inconsistent. + We can solve these problems in mixed mode by switching to binlogging + if at least one updated table is used by sub-statement */ - if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED && - has_two_write_locked_tables_with_auto_increment(tables)) + /* The BINLOG_FORMAT_MIXED judgement is saved for suppressing + warnings, but it will be removed by fixing bug#45827 */ + if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED && tables && + has_write_table_with_auto_increment(thd->lex->first_not_own_table())) { thd->lex->set_stmt_unsafe(); - thd->set_current_stmt_binlog_row_based_if_mixed(); } } + DEBUG_SYNC(thd, "before_lock_tables_takes_lock"); + if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start), lock_flag, need_reopen))) { @@ -8830,47 +8849,31 @@ void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table /* - Tells if two (or more) tables have auto_increment columns and we want to - lock those tables with a write lock. + Check if one (or more) write tables have auto_increment columns. - SYNOPSIS - has_two_write_locked_tables_with_auto_increment - tables Table list + @param[in] tables Table list + + @retval 0 if at least one write tables has an auto_increment column + @retval 1 otherwise NOTES: Call this function only when you have established the list of all tables which you'll want to update (including stored functions, triggers, views inside your statement). - - RETURN - 0 No - 1 Yes */ static bool -has_two_write_locked_tables_with_auto_increment(TABLE_LIST *tables) +has_write_table_with_auto_increment(TABLE_LIST *tables) { - char *first_table_name= NULL, *first_db; - LINT_INIT(first_db); - for (TABLE_LIST *table= tables; table; table= table->next_global) { /* we must do preliminary checks as table->table may be NULL */ if (!table->placeholder() && table->table->found_next_number_field && (table->lock_type >= TL_WRITE_ALLOW_WRITE)) - { - if (first_table_name == NULL) - { - first_table_name= table->table_name; - first_db= table->db; - DBUG_ASSERT(first_db); - } - else if (strcmp(first_db, table->db) || - strcmp(first_table_name, table->table_name)) - return 1; - } + return 1; } + return 0; } diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 67f2912fe7b..07972d9b3e4 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -56,17 +56,20 @@ void mysql_client_binlog_statement(THD* thd) Format_description_event. */ my_bool have_fd_event= TRUE; - if (!thd->rli_fake) + int err; + Relay_log_info *rli; + rli= thd->rli_fake; + if (!rli) { - thd->rli_fake= new Relay_log_info; + rli= thd->rli_fake= new Relay_log_info; #ifdef HAVE_valgrind - thd->rli_fake->is_fake= TRUE; + rli->is_fake= TRUE; #endif have_fd_event= FALSE; } - if (thd->rli_fake && !thd->rli_fake->relay_log.description_event_for_exec) + if (rli && !rli->relay_log.description_event_for_exec) { - thd->rli_fake->relay_log.description_event_for_exec= + rli->relay_log.description_event_for_exec= new Format_description_log_event(4); have_fd_event= FALSE; } @@ -78,16 +81,16 @@ void mysql_client_binlog_statement(THD* thd) /* Out of memory check */ - if (!(thd->rli_fake && - thd->rli_fake->relay_log.description_event_for_exec && + if (!(rli && + rli->relay_log.description_event_for_exec && buf)) { my_error(ER_OUTOFMEMORY, MYF(0), 1); /* needed 1 bytes */ goto end; } - thd->rli_fake->sql_thd= thd; - thd->rli_fake->no_storage= TRUE; + rli->sql_thd= thd; + rli->no_storage= TRUE; for (char const *strptr= thd->lex->comment.str ; strptr < thd->lex->comment.str + thd->lex->comment.length ; ) @@ -170,8 +173,7 @@ void mysql_client_binlog_statement(THD* thd) } ev= Log_event::read_log_event(bufptr, event_len, &error, - thd->rli_fake->relay_log. - description_event_for_exec); + rli->relay_log.description_event_for_exec); DBUG_PRINT("info",("binlog base64 err=%s", error)); if (!ev) @@ -209,18 +211,10 @@ void mysql_client_binlog_statement(THD* thd) reporting. */ #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) - if (apply_event_and_update_pos(ev, thd, thd->rli_fake, FALSE)) - { - delete ev; - /* - TODO: Maybe a better error message since the BINLOG statement - now contains several events. - */ - my_error(ER_UNKNOWN_ERROR, MYF(0), "Error executing BINLOG statement"); - goto end; - } + err= ev->apply_event(rli); +#else + err= 0; #endif - /* Format_description_log_event should not be deleted because it will be used to read info about the relay log's format; it @@ -228,8 +222,17 @@ void mysql_client_binlog_statement(THD* thd) i.e. when this thread terminates. */ if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT) - delete ev; + delete ev; ev= 0; + if (err) + { + /* + TODO: Maybe a better error message since the BINLOG statement + now contains several events. + */ + my_error(ER_UNKNOWN_ERROR, MYF(0), "Error executing BINLOG statement"); + goto end; + } } } @@ -238,7 +241,7 @@ void mysql_client_binlog_statement(THD* thd) my_ok(thd); end: - thd->rli_fake->clear_tables_to_lock(); + rli->clear_tables_to_lock(); my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); DBUG_VOID_RETURN; } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 3465362da01..f995b51ae68 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1119,8 +1119,8 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) DBUG_VOID_RETURN; uint8 tables_type= 0; - if ((local_tables= is_cacheable(thd, thd->query_length, - thd->query, thd->lex, tables_used, + if ((local_tables= is_cacheable(thd, thd->query_length(), + thd->query(), thd->lex, tables_used, &tables_type))) { NET *net= &thd->net; @@ -1210,7 +1210,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", /* Key is query + database + flag */ if (thd->db_length) { - memcpy(thd->query+thd->query_length+1, thd->db, thd->db_length); + memcpy(thd->query() + thd->query_length() + 1, thd->db, + thd->db_length); DBUG_PRINT("qcache", ("database: %s length: %u", thd->db, (unsigned) thd->db_length)); } @@ -1218,24 +1219,24 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", { DBUG_PRINT("qcache", ("No active database")); } - tot_length= thd->query_length + thd->db_length + 1 + + tot_length= thd->query_length() + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE; /* We should only copy structure (don't use it location directly) because of alignment issue */ - memcpy((void *)(thd->query + (tot_length - QUERY_CACHE_FLAGS_SIZE)), + memcpy((void*) (thd->query() + (tot_length - QUERY_CACHE_FLAGS_SIZE)), &flags, QUERY_CACHE_FLAGS_SIZE); /* Check if another thread is processing the same query? */ Query_cache_block *competitor = (Query_cache_block *) - hash_search(&queries, (uchar*) thd->query, tot_length); + hash_search(&queries, (uchar*) thd->query(), tot_length); DBUG_PRINT("qcache", ("competitor 0x%lx", (ulong) competitor)); if (competitor == 0) { /* Query is not in cache and no one is working with it; Store it */ Query_cache_block *query_block; - query_block= write_block_data(tot_length, (uchar*) thd->query, + query_block= write_block_data(tot_length, (uchar*) thd->query(), ALIGN_SIZE(sizeof(Query_cache_query)), Query_cache_block::QUERY, local_tables); if (query_block != 0) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0805eda59e4..abaa2b8c202 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -42,6 +42,7 @@ #include "sp_rcontext.h" #include "sp_cache.h" +#include "debug_sync.h" /* The following is used to initialise Table_ident with a internal @@ -378,14 +379,14 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, str.append(proc_info); } - if (thd->query) + if (thd->query()) { if (max_query_len < 1) - len= thd->query_length; + len= thd->query_length(); else - len= min(thd->query_length, max_query_len); + len= min(thd->query_length(), max_query_len); str.append('\n'); - str.append(thd->query, len); + str.append(thd->query(), len); } if (str.c_ptr_safe() == buffer) return buffer; @@ -402,6 +403,31 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, return buffer; } + +/** + Implementation of Drop_table_error_handler::handle_error(). + The reason in having this implementation is to silence technical low-level + warnings during DROP TABLE operation. Currently we don't want to expose + the following warnings during DROP TABLE: + - Some of table files are missed or invalid (the table is going to be + deleted anyway, so why bother that something was missed); + - A trigger associated with the table does not have DEFINER (One of the + MySQL specifics now is that triggers are loaded for the table being + dropped. So, we may have a warning that trigger does not have DEFINER + attribute during DROP TABLE operation). + + @return TRUE if the condition is handled. +*/ +bool Drop_table_error_handler::handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd) +{ + return ((sql_errno == EE_DELETE && my_errno == ENOENT) || + sql_errno == ER_TRG_NO_DEFINER); +} + + /** Clear this diagnostics area. @@ -564,6 +590,9 @@ THD::THD() derived_tables_processing(FALSE), spcont(NULL), m_parser_state(NULL) +#if defined(ENABLED_DEBUG_SYNC) + , debug_sync_control(0) +#endif /* defined(ENABLED_DEBUG_SYNC) */ { ulong tmp; @@ -702,17 +731,13 @@ void THD::push_internal_handler(Internal_error_handler *handler) bool THD::handle_error(uint sql_errno, const char *message, MYSQL_ERROR::enum_warning_level level) { - if (!m_internal_handler) - return FALSE; - for (Internal_error_handler *error_handler= m_internal_handler; error_handler; error_handler= m_internal_handler->m_prev_internal_handler) { if (error_handler->handle_error(sql_errno, message, level, this)) - return TRUE; + return TRUE; } - return FALSE; } @@ -818,6 +843,11 @@ void THD::init(void) reset_current_stmt_binlog_row_based(); bzero((char *) &status_var, sizeof(status_var)); sql_log_bin_toplevel= options & OPTION_BIN_LOG; + +#if defined(ENABLED_DEBUG_SYNC) + /* Initialize the Debug Sync Facility. See debug_sync.cc. */ + debug_sync_init_thread(this); +#endif /* defined(ENABLED_DEBUG_SYNC) */ } @@ -898,6 +928,12 @@ void THD::cleanup(void) close_thread_tables(this); } wt_thd_destroy(&transaction.wt); + +#if defined(ENABLED_DEBUG_SYNC) + /* End the Debug Sync Facility. See debug_sync.cc. */ + debug_sync_end_thread(this); +#endif /* defined(ENABLED_DEBUG_SYNC) */ + mysql_ha_cleanup(this); delete_dynamic(&user_var_events); hash_free(&user_vars); @@ -2449,12 +2485,12 @@ Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg, id(id_arg), mark_used_columns(MARK_COLUMNS_READ), lex(lex_arg), - query(0), - query_length(0), cursor(0), db(NULL), db_length(0) { + query_string.length= 0; + query_string.str= NULL; name.str= NULL; } @@ -2470,8 +2506,7 @@ void Statement::set_statement(Statement *stmt) id= stmt->id; mark_used_columns= stmt->mark_used_columns; lex= stmt->lex; - query= stmt->query; - query_length= stmt->query_length; + query_string= stmt->query_string; cursor= stmt->cursor; } @@ -2495,6 +2530,15 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup) } +/** Assign a new value to thd->query. */ + +void Statement::set_query_inner(char *query_arg, uint32 query_length_arg) +{ + query_string.str= query_arg; + query_string.length= query_length_arg; +} + + void THD::end_statement() { /* Cleanup SQL processing state to reuse this statement in next query. */ @@ -2730,9 +2774,11 @@ bool select_dumpvar::send_data(List<Item> &items) else { Item_func_set_user_var *suv= new Item_func_set_user_var(mv->s, item); - suv->fix_fields(thd, 0); + if (suv->fix_fields(thd, 0)) + DBUG_RETURN (1); suv->save_item_result(item); - suv->update(); + if (suv->update()) + DBUG_RETURN (1); } } DBUG_RETURN(thd->is_error()); @@ -3008,9 +3054,24 @@ extern "C" struct charset_info_st *thd_charset(MYSQL_THD thd) return(thd->charset()); } +/** + OBSOLETE : there's no way to ensure the string is null terminated. + Use thd_query_string instead() +*/ extern "C" char **thd_query(MYSQL_THD thd) { - return(&thd->query); + return(&thd->query_string.str); +} + +/** + Get the current query string for the thread. + + @param The MySQL internal thread pointer + @return query string and length. May be non-null-terminated. +*/ +extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd) +{ + return(&thd->query_string); } extern "C" int thd_slave_thread(const MYSQL_THD thd) @@ -3035,6 +3096,11 @@ extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all) { mark_transaction_to_rollback(thd, all); } + +extern "C" bool thd_binlog_filter_ok(const MYSQL_THD thd) +{ + return binlog_filter->db_ok(thd->db); +} #endif // INNODB_COMPATIBILITY_HOOKS */ /**************************************************************************** @@ -3191,8 +3257,7 @@ void THD::set_statement(Statement *stmt) void THD::set_query(char *query_arg, uint32 query_length_arg) { pthread_mutex_lock(&LOCK_thd_data); - query= query_arg; - query_length= query_length_arg; + set_query_inner(query_arg, query_length_arg); pthread_mutex_unlock(&LOCK_thd_data); } @@ -3210,6 +3275,16 @@ void mark_transaction_to_rollback(THD *thd, bool all) { thd->is_fatal_sub_stmt_error= TRUE; thd->transaction_rollback_request= all; + /* + Aborted transactions can not be IGNOREd. + Switch off the IGNORE flag for the current + SELECT_LEX. This should allow my_error() + to report the error and abort the execution + flow, even in presence + of IGNORE clause. + */ + if (thd->lex->current_select) + thd->lex->current_select->no_error= FALSE; } } /*************************************************************************** diff --git a/sql/sql_class.h b/sql/sql_class.h index 60ab952a3ab..2ed4a7a3c0a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -95,6 +95,8 @@ extern char internal_table_name[2]; extern char empty_c_string[1]; extern MYSQL_PLUGIN_IMPORT const char **errmesg; +extern bool volatile shutdown_in_progress; + #define TC_LOG_PAGE_SIZE 8192 #define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE) @@ -652,10 +654,13 @@ public: This printing is needed at least in SHOW PROCESSLIST and SHOW ENGINE INNODB STATUS. */ - char *query; - uint32 query_length; // current query length + LEX_STRING query_string; Server_side_cursor *cursor; + inline char *query() { return query_string.str; } + inline uint32 query_length() { return query_string.length; } + void set_query_inner(char *query_arg, uint32 query_length_arg); + /** Name of the current (default) database. @@ -1103,6 +1108,31 @@ public: /** + This class is an internal error handler implementation for + DROP TABLE statements. The thing is that there may be warnings during + execution of these statements, which should not be exposed to the user. + This class is intended to silence such warnings. +*/ + +class Drop_table_error_handler : public Internal_error_handler +{ +public: + Drop_table_error_handler(Internal_error_handler *err_handler) + :m_err_handler(err_handler) + { } + +public: + bool handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd); + +private: + Internal_error_handler *m_err_handler; +}; + + +/** Stores status of the currently executed statement. Cleared at the beginning of the statement, and then can hold either OK, ERROR, or EOF status. @@ -1888,6 +1918,11 @@ public: partition_info *work_part_info; #endif +#if defined(ENABLED_DEBUG_SYNC) + /* Debug Sync facility. See debug_sync.cc. */ + struct st_debug_sync_control *debug_sync_control; +#endif /* defined(ENABLED_DEBUG_SYNC) */ + THD(); ~THD(); @@ -2124,7 +2159,11 @@ public: { int err= killed_errno(); if (err) + { + if ((err == KILL_CONNECTION) && !shutdown_in_progress) + err = KILL_QUERY; my_message(err, ER(err), MYF(0)); + } } /* return TRUE if we will abort query if we make a warning now */ inline bool really_abort_on_warning() @@ -2641,7 +2680,32 @@ public: ENGINE_COLUMNDEF *recinfo, *start_recinfo; KEY *keyinfo; ha_rows end_write_records; - uint field_count,sum_func_count,func_count; + /** + Number of normal fields in the query, including those referred to + from aggregate functions. Hence, "SELECT `field1`, + SUM(`field2`) from t1" sets this counter to 2. + + @see count_field_types + */ + uint field_count; + /** + Number of fields in the query that have functions. Includes both + aggregate functions (e.g., SUM) and non-aggregates (e.g., RAND). + Also counts functions referred to from aggregate functions, i.e., + "SELECT SUM(RAND())" sets this counter to 2. + + @see count_field_types + */ + uint func_count; + /** + Number of fields in the query that have aggregate functions. Note + that the optimizer may choose to optimize away these fields by + replacing them with constants, in which case sum_func_count will + need to be updated. + + @see opt_sum_query, count_field_types + */ + uint sum_func_count; uint hidden_field_count; uint group_parts,group_length,group_null_parts; uint quick_group; @@ -2906,7 +2970,8 @@ public: bool send_data(List<Item> &items); bool initialize_tables (JOIN *join); void send_error(uint errcode,const char *err); - int do_deletes(); + int do_deletes(); + int do_table_deletes(TABLE *table, bool ignore); bool send_eof(); virtual void abort(); }; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 82f5bf48166..adc1aab9976 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -703,7 +703,7 @@ not_silent: char *query; uint query_length; - if (!thd->query) // Only in replication + if (!thd->query()) // Only in replication { query= tmp_query; query_length= (uint) (strxmov(tmp_query,"create database `", @@ -711,8 +711,8 @@ not_silent: } else { - query= thd->query; - query_length= thd->query_length; + query= thd->query(); + query_length= thd->query_length(); } ha_binlog_log_query(thd, 0, LOGCOM_CREATE_DB, @@ -805,13 +805,13 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) } ha_binlog_log_query(thd, 0, LOGCOM_ALTER_DB, - thd->query, thd->query_length, + thd->query(), thd->query_length(), db, ""); if (mysql_bin_log.is_open()) { int errcode= query_error_code(thd, TRUE); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, + Query_log_event qinfo(thd, thd->query(), thd->query_length(), 0, /* suppress_use */ TRUE, errcode); /* @@ -907,6 +907,9 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) remove_db_from_cache(db); pthread_mutex_unlock(&LOCK_open); + Drop_table_error_handler err_handler(thd->get_internal_handler()); + thd->push_internal_handler(&err_handler); + error= -1; /* We temporarily disable the binary log while dropping the objects @@ -939,12 +942,13 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) error = 0; reenable_binlog(thd); } + thd->pop_internal_handler(); } if (!silent && deleted>=0) { const char *query; ulong query_length; - if (!thd->query) + if (!thd->query()) { /* The client used the old obsolete mysql_drop_db() call */ query= path; @@ -953,8 +957,8 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) } else { - query =thd->query; - query_length= thd->query_length; + query= thd->query(); + query_length= thd->query_length(); } if (mysql_bin_log.is_open()) { @@ -1444,7 +1448,7 @@ static inline bool cmp_db_names(const char *db1_name, const char *db2_name) { - return ((!db1_name && !db2_name) || /* db1 is NULL and db2 is NULL */ + return ((!db1_name && !db2_name) || (db1_name && db2_name && my_strcasecmp(system_charset_info, db1_name, db2_name) == 0)); } @@ -1956,7 +1960,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db) if (mysql_bin_log.is_open()) { int errcode= query_error_code(thd, TRUE); - Query_log_event qinfo(thd, thd->query, thd->query_length, + Query_log_event qinfo(thd, thd->query(), thd->query_length(), 0, TRUE, errcode); thd->clear_error(); mysql_bin_log.write(&qinfo); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 8a5afa8da17..6587962bd56 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -413,7 +413,7 @@ cleanup: therefore be treated as a DDL. */ int log_result= thd->binlog_query(query_type, - thd->query, thd->query_length, + thd->query(), thd->query_length(), is_trans, FALSE, errcode); if (log_result) @@ -850,7 +850,7 @@ void multi_delete::abort() { int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), transactional_tables, FALSE, errcode); } thd->transaction.all.modified_non_trans_table= true; @@ -860,22 +860,19 @@ void multi_delete::abort() -/* +/** Do delete from other tables. - Returns values: - 0 ok - 1 error + + @retval 0 ok + @retval 1 error + + @todo Is there any reason not use the normal nested-loops join? If not, and + there is no documentation supporting it, this method and callee should be + removed and there should be hooks within normal execution. */ int multi_delete::do_deletes() { - int local_error= 0, counter= 0, tmp_error; - bool will_batch; - /* - If the IGNORE option is used all non fatal errors will be translated - to warnings and we should not break the row-by-row iteration - */ - bool ignore= thd->lex->current_select->no_error; DBUG_ENTER("do_deletes"); DBUG_ASSERT(do_delete); @@ -886,79 +883,108 @@ int multi_delete::do_deletes() table_being_deleted= (delete_while_scanning ? delete_tables->next_local : delete_tables); - for (; table_being_deleted; + for (uint counter= 0; table_being_deleted; table_being_deleted= table_being_deleted->next_local, counter++) { - ha_rows last_deleted= deleted; TABLE *table = table_being_deleted->table; if (tempfiles[counter]->get(table)) + DBUG_RETURN(1); + + int local_error= + do_table_deletes(table, thd->lex->current_select->no_error); + + if (thd->killed && !local_error) + DBUG_RETURN(1); + + if (local_error == -1) // End of file + local_error = 0; + + if (local_error) + DBUG_RETURN(local_error); + } + DBUG_RETURN(0); +} + + +/** + Implements the inner loop of nested-loops join within multi-DELETE + execution. + + @param table The table from which to delete. + + @param ignore If used, all non fatal errors will be translated + to warnings and we should not break the row-by-row iteration. + + @return Status code + + @retval 0 All ok. + @retval 1 Triggers or handler reported error. + @retval -1 End of file from handler. +*/ +int multi_delete::do_table_deletes(TABLE *table, bool ignore) +{ + int local_error= 0; + READ_RECORD info; + ha_rows last_deleted= deleted; + DBUG_ENTER("do_deletes_for_table"); + init_read_record(&info, thd, table, NULL, 0, 1, FALSE); + /* + Ignore any rows not found in reference tables as they may already have + been deleted by foreign key handling + */ + info.ignore_not_found_rows= 1; + bool will_batch= !table->file->start_bulk_delete(); + while (!(local_error= info.read_record(&info)) && !thd->killed) + { + if (table->triggers && + table->triggers->process_triggers(thd, TRG_EVENT_DELETE, + TRG_ACTION_BEFORE, FALSE)) { - local_error=1; + local_error= 1; break; } - - READ_RECORD info; - init_read_record(&info, thd, table, NULL, 0, 1, FALSE); + + local_error= table->file->ha_delete_row(table->record[0]); + if (local_error && !ignore) + { + table->file->print_error(local_error, MYF(0)); + break; + } + /* - Ignore any rows not found in reference tables as they may already have - been deleted by foreign key handling + Increase the reported number of deleted rows only if no error occurred + during ha_delete_row. + Also, don't execute the AFTER trigger if the row operation failed. */ - info.ignore_not_found_rows= 1; - will_batch= !table->file->start_bulk_delete(); - while (!(local_error=info.read_record(&info)) && !thd->killed) + if (!local_error) { + deleted++; if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, - TRG_ACTION_BEFORE, FALSE)) + TRG_ACTION_AFTER, FALSE)) { local_error= 1; break; } - - local_error= table->file->ha_delete_row(table->record[0]); - if (local_error && !ignore) - { - table->file->print_error(local_error,MYF(0)); - break; - } - - /* - Increase the reported number of deleted rows only if no error occurred - during ha_delete_row. - Also, don't execute the AFTER trigger if the row operation failed. - */ - if (!local_error) - { - deleted++; - if (table->triggers && - table->triggers->process_triggers(thd, TRG_EVENT_DELETE, - TRG_ACTION_AFTER, FALSE)) - { - local_error= 1; - break; - } - } } - if (will_batch && (tmp_error= table->file->end_bulk_delete())) + } + if (will_batch) + { + int tmp_error= table->file->end_bulk_delete(); + if (tmp_error && !local_error) { - if (!local_error) - { - local_error= tmp_error; - table->file->print_error(local_error,MYF(0)); - } + local_error= tmp_error; + table->file->print_error(local_error, MYF(0)); } - if (last_deleted != deleted && !table->file->has_transactions()) - thd->transaction.stmt.modified_non_trans_table= TRUE; - end_read_record(&info); - if (thd->killed && !local_error) - local_error= 1; - if (local_error == -1) // End of file - local_error = 0; } + if (last_deleted != deleted && !table->file->has_transactions()) + thd->transaction.stmt.modified_non_trans_table= TRUE; + + end_read_record(&info); + DBUG_RETURN(local_error); } - /* Send ok to the client @@ -998,7 +1024,7 @@ bool multi_delete::send_eof() else errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); if (thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), transactional_tables, FALSE, errcode) && !normal_tables) { @@ -1144,7 +1170,7 @@ end: TRUNCATE must always be statement-based binlogged (not row-based) so we don't test current_stmt_binlog_row_based. */ - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); my_ok(thd); // This should return record count } VOID(pthread_mutex_lock(&LOCK_open)); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 1e92d95573a..3bbf4b78d07 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -422,16 +422,13 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, String buffer(buff, sizeof(buff), system_charset_info); int error, keyno= -1; uint num_rows; - uchar *key; - uint key_len; + uchar *UNINIT_VAR(key); + uint UNINIT_VAR(key_len); bool need_reopen; DBUG_ENTER("mysql_ha_read"); DBUG_PRINT("enter",("'%s'.'%s' as '%s'", tables->db, tables->table_name, tables->alias)); - LINT_INIT(key); - LINT_INIT(key_len); - thd->lex->select_lex.context.resolve_in_table_list_only(tables); list.push_front(new Item_field(&thd->lex->select_lex.context, NULL, NULL, "*")); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 0cd67a16a25..9b2a45618b2 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -589,7 +589,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, Name_resolution_context *context; Name_resolution_context_state ctx_state; #ifndef EMBEDDED_LIBRARY - char *query= thd->query; + char *query= thd->query(); /* log_on is about delayed inserts only. By default, both logs are enabled (this won't cause problems if the server @@ -826,7 +826,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, #ifndef EMBEDDED_LIBRARY if (lock_type == TL_WRITE_DELAYED) { - LEX_STRING const st_query = { query, thd->query_length }; + LEX_STRING const st_query = { query, thd->query_length() }; error=write_delayed(thd, table, duplic, st_query, ignore, log_on); query=0; } @@ -919,7 +919,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, */ DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0); if (thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), transactional_table, FALSE, errcode)) { @@ -1791,7 +1791,7 @@ public: pthread_cond_destroy(&cond); pthread_cond_destroy(&cond_client); thd.unlink(); // Must be unlinked under lock - x_free(thd.query); + x_free(thd.query()); thd.security_ctx->user= thd.security_ctx->host=0; thread_count--; delayed_insert_threads--; @@ -1937,7 +1937,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) pthread_mutex_unlock(&LOCK_thread_count); di->thd.set_db(table_list->db, (uint) strlen(table_list->db)); di->thd.set_query(my_strdup(table_list->table_name, MYF(MY_WME)), 0); - if (di->thd.db == NULL || di->thd.query == NULL) + if (di->thd.db == NULL || di->thd.query() == NULL) { /* The error is reported */ delete di; @@ -1946,7 +1946,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) } di->table_list= *table_list; // Needed to open table /* Replace volatile strings with local copies */ - di->table_list.alias= di->table_list.table_name= di->thd.query; + di->table_list.alias= di->table_list.table_name= di->thd.query(); di->table_list.db= di->thd.db; di->lock(); pthread_mutex_lock(&di->mutex); @@ -2302,44 +2302,9 @@ void kill_delayed_threads(void) } -/* - * Create a new delayed insert thread -*/ - -pthread_handler_t handle_delayed_insert(void *arg) +static void handle_delayed_insert_impl(THD *thd, Delayed_insert *di) { - Delayed_insert *di=(Delayed_insert*) arg; - THD *thd= &di->thd; - - pthread_detach_this_thread(); - /* Add thread to THD list so that's it's visible in 'show processlist' */ - pthread_mutex_lock(&LOCK_thread_count); - thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; - thd->set_current_time(); - threads.append(thd); - thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED; - pthread_mutex_unlock(&LOCK_thread_count); - - /* - Wait until the client runs into pthread_cond_wait(), - where we free it after the table is opened and di linked in the list. - If we did not wait here, the client might detect the opened table - before it is linked to the list. It would release LOCK_delayed_create - and allow another thread to create another handler for the same table, - since it does not find one in the list. - */ - pthread_mutex_lock(&di->mutex); -#if !defined( __WIN__) /* Win32 calls this in pthread_create */ - if (my_thread_init()) - { - /* Can't use my_error since store_globals has not yet been called */ - thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES, - ER(ER_OUT_OF_RESOURCES)); - goto end; - } -#endif - - DBUG_ENTER("handle_delayed_insert"); + DBUG_ENTER("handle_delayed_insert_impl"); thd->thread_stack= (char*) &thd; if (init_thr_lock() || thd->store_globals()) { @@ -2528,6 +2493,49 @@ err: */ ha_autocommit_or_rollback(thd, 1); + DBUG_VOID_RETURN; +} + + +/* + * Create a new delayed insert thread +*/ + +pthread_handler_t handle_delayed_insert(void *arg) +{ + Delayed_insert *di=(Delayed_insert*) arg; + THD *thd= &di->thd; + + pthread_detach_this_thread(); + /* Add thread to THD list so that's it's visible in 'show processlist' */ + pthread_mutex_lock(&LOCK_thread_count); + thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; + thd->set_current_time(); + threads.append(thd); + thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED; + pthread_mutex_unlock(&LOCK_thread_count); + + /* + Wait until the client runs into pthread_cond_wait(), + where we free it after the table is opened and di linked in the list. + If we did not wait here, the client might detect the opened table + before it is linked to the list. It would release LOCK_delayed_create + and allow another thread to create another handler for the same table, + since it does not find one in the list. + */ + pthread_mutex_lock(&di->mutex); +#if !defined( __WIN__) /* Win32 calls this in pthread_create */ + if (my_thread_init()) + { + /* Can't use my_error since store_globals has not yet been called */ + thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES, + ER(ER_OUT_OF_RESOURCES)); + goto end; + } +#endif + + handle_delayed_insert_impl(thd, di); + #ifndef __WIN__ end: #endif @@ -2552,7 +2560,8 @@ end: my_thread_end(); pthread_exit(0); - DBUG_RETURN(0); + + return 0; } @@ -3269,7 +3278,7 @@ bool select_insert::send_eof() else errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), trans_table, FALSE, errcode); } table->file->ha_release_auto_increment(); @@ -3339,7 +3348,8 @@ void select_insert::abort() { if (mysql_bin_log.is_open()) { int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); - thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, + thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), + thd->query_length(), transactional_table, FALSE, errcode); } if (!thd->current_stmt_binlog_row_based && !can_rollback_data()) @@ -3633,7 +3643,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) DBUG_EXECUTE_IF("sleep_create_select_before_check_if_exists", my_sleep(6000000);); if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE) && - create_table->table->db_stat) + (create_table->table && create_table->table->db_stat)) { /* Table already exists and was open at open_and_lock_tables() stage. */ if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4b9b35819fe..5e37e618250 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1735,13 +1735,6 @@ typedef struct st_lex : public Query_tables_list const char *stmt_definition_end; - /* - Pointers to part of LOAD DATA statement that should be rewritten - during replication ("LOCAL 'filename' REPLACE INTO" part). - */ - const char *fname_start; - const char *fname_end; - /** During name resolution search only in the table list given by Name_resolution_context::first_name_resolution_table and diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 1929c233f23..2467116d8dc 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -83,10 +83,13 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, String &enclosed, ulong skip_lines, bool ignore_check_option_errors); #ifndef EMBEDDED_LIBRARY -static bool write_execute_load_query_log_event(THD *thd, - bool duplicates, bool ignore, - bool transactional_table, - int errcode); +static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, + const char* db_arg, /* table's database */ + const char* table_name_arg, + enum enum_duplicates duplicates, + bool ignore, + bool transactional_table, + int errocode); #endif /* EMBEDDED_LIBRARY */ /* @@ -497,8 +500,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); if (thd->transaction.stmt.modified_non_trans_table) - write_execute_load_query_log_event(thd, handle_duplicates, - ignore, transactional_table, + write_execute_load_query_log_event(thd, ex, + table_list->db, + table_list->table_name, + handle_duplicates, ignore, + transactional_table, errcode); else { @@ -542,8 +548,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (lf_info.wrote_create_file) { int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); - write_execute_load_query_log_event(thd, handle_duplicates, ignore, - transactional_table, errcode); + write_execute_load_query_log_event(thd, ex, + table_list->db, table_list->table_name, + handle_duplicates, ignore, + transactional_table, + errcode); } } } @@ -564,15 +573,113 @@ err: #ifndef EMBEDDED_LIBRARY /* Not a very useful function; just to avoid duplication of code */ -static bool write_execute_load_query_log_event(THD *thd, - bool duplicates, bool ignore, - bool transactional_table, +static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, + const char* db_arg, /* table's database */ + const char* table_name_arg, + enum enum_duplicates duplicates, + bool ignore, + bool transactional_table, int errcode) { + char *load_data_query, + *end, + *fname_start, + *fname_end, + *p= NULL; + size_t pl= 0; + List<Item> fv; + Item *item, *val; + String pfield, pfields; + int n; + const char *tbl= table_name_arg; + const char *tdb= (thd->db != NULL ? thd->db : db_arg); + String string_buf; + + if (!thd->db || strcmp(db_arg, thd->db)) + { + /* + If used database differs from table's database, + prefix table name with database name so that it + becomes a FQ name. + */ + string_buf.set_charset(system_charset_info); + string_buf.append(db_arg); + string_buf.append("`"); + string_buf.append("."); + string_buf.append("`"); + string_buf.append(table_name_arg); + tbl= string_buf.c_ptr_safe(); + } + + Load_log_event lle(thd, ex, tdb, tbl, fv, duplicates, + ignore, transactional_table); + + /* + force in a LOCAL if there was one in the original. + */ + if (thd->lex->local_file) + lle.set_fname_outside_temp_buf(ex->file_name, strlen(ex->file_name)); + + /* + prepare fields-list and SET if needed; print_query won't do that for us. + */ + if (!thd->lex->field_list.is_empty()) + { + List_iterator<Item> li(thd->lex->field_list); + + pfields.append(" ("); + n= 0; + + while ((item= li++)) + { + if (n++) + pfields.append(", "); + if (item->name) + pfields.append(item->name); + else + item->print(&pfields, QT_ORDINARY); + } + pfields.append(")"); + } + + if (!thd->lex->update_list.is_empty()) + { + List_iterator<Item> lu(thd->lex->update_list); + List_iterator<Item> lv(thd->lex->value_list); + + pfields.append(" SET "); + n= 0; + + while ((item= lu++)) + { + val= lv++; + if (n++) + pfields.append(", "); + pfields.append(item->name); + pfields.append("="); + val->print(&pfields, QT_ORDINARY); + } + } + + p= pfields.c_ptr_safe(); + pl= strlen(p); + + if (!(load_data_query= (char *)thd->alloc(lle.get_query_buffer_length() + 1 + pl))) + return TRUE; + + lle.print_query(FALSE, (const char *) ex->cs?ex->cs->csname:NULL, + load_data_query, &end, + (char **)&fname_start, (char **)&fname_end); + + strcpy(end, p); + end += pl; + + thd->set_query_inner(load_data_query, end - load_data_query); + Execute_load_query_log_event - e(thd, thd->query, thd->query_length, - (uint) ((char*)thd->lex->fname_start - (char*)thd->query), - (uint) ((char*)thd->lex->fname_end - (char*)thd->query), + e(thd, thd->query(), thd->query_length(), + (uint) ((char*) fname_start - (char*) thd->query() - 1), + (uint) ((char*) fname_end - (char*) thd->query()), (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE : (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR), transactional_table, FALSE, errcode); diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index 3def9864c29..5ddf65cd1b7 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -1309,9 +1309,9 @@ static const char *my_locale_month_names_ro_RO[13] = static const char *my_locale_ab_month_names_ro_RO[13] = {"ian","feb","mar","apr","mai","iun","iul","aug","sep","oct","nov","dec", NullS }; static const char *my_locale_day_names_ro_RO[8] = - {"Luni","MarÅ£i","Miercuri","Joi","Vineri","SîmbÄ‚tÄ‚","DuminicÄ‚", NullS }; + {"Luni","MarÅ£i","Miercuri","Joi","Vineri","Sâmbătă","Duminică", NullS }; static const char *my_locale_ab_day_names_ro_RO[8] = - {"Lu","Ma","Mi","Jo","Vi","Sî","Du", NullS }; + {"Lu","Ma","Mi","Jo","Vi","Sâ","Du", NullS }; static TYPELIB my_locale_typelib_month_names_ro_RO = { array_elements(my_locale_month_names_ro_RO)-1, "", my_locale_month_names_ro_RO, NULL }; static TYPELIB my_locale_typelib_ab_month_names_ro_RO = diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index df8d131df59..900c59419ad 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -126,6 +126,14 @@ static bool xa_trans_rolled_back(XID_STATE *xid_state) */ static bool xa_trans_rollback(THD *thd) { + /* + Resource Manager error is meaningless at this point, as we perform + explicit rollback request by user. We must reset rm_error before + calling ha_rollback(), so thd->transaction.xid structure gets reset + by ha_rollback()/THD::transaction::cleanup(). + */ + thd->transaction.xid_state.rm_error= 0; + bool status= test(ha_rollback(thd)); thd->options&= ~(ulong) OPTION_BEGIN; @@ -133,7 +141,6 @@ static bool xa_trans_rollback(THD *thd) thd->server_status&= ~SERVER_STATUS_IN_TRANS; xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state= XA_NOTR; - thd->transaction.xid_state.rm_error= 0; return status; } @@ -415,29 +422,12 @@ void execute_init_command(THD *thd, sys_var_str *init_command_var, } -/** - Execute commands from bootstrap_file. - - Used when creating the initial grant tables. -*/ - -pthread_handler_t handle_bootstrap(void *arg) +static void handle_bootstrap_impl(THD *thd) { - THD *thd=(THD*) arg; FILE *file=bootstrap_file; char *buff; const char* found_semicolon= NULL; - /* The following must be called before DBUG_ENTER */ - thd->thread_stack= (char*) &thd; - if (my_thread_init() || thd->store_globals()) - { -#ifndef EMBEDDED_LIBRARY - close_connection(thd, ER_OUT_OF_RESOURCES, 1); -#endif - thd->fatal_error(); - goto end; - } DBUG_ENTER("handle_bootstrap"); #ifndef EMBEDDED_LIBRARY @@ -505,10 +495,10 @@ pthread_handler_t handle_bootstrap(void *arg) thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE); thd->set_query(query, length); - DBUG_PRINT("query",("%-.4096s",thd->query)); + DBUG_PRINT("query",("%-.4096s", thd->query())); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.start_new_query(); - thd->profiling.set_query_source(thd->query, length); + thd->profiling.set_query_source(thd->query(), length); #endif /* @@ -517,7 +507,7 @@ pthread_handler_t handle_bootstrap(void *arg) */ thd->query_id=next_query_id(); thd->set_time(); - mysql_parse(thd, thd->query, length, & found_semicolon); + mysql_parse(thd, thd->query(), length, & found_semicolon); close_thread_tables(thd); // Free tables bootstrap_error= thd->is_error(); @@ -536,6 +526,33 @@ pthread_handler_t handle_bootstrap(void *arg) #endif } + DBUG_VOID_RETURN; +} + + +/** + Execute commands from bootstrap_file. + + Used when creating the initial grant tables. +*/ + +pthread_handler_t handle_bootstrap(void *arg) +{ + THD *thd=(THD*) arg; + + /* The following must be called before DBUG_ENTER */ + thd->thread_stack= (char*) &thd; + if (my_thread_init() || thd->store_globals()) + { +#ifndef EMBEDDED_LIBRARY + close_connection(thd, ER_OUT_OF_RESOURCES, 1); +#endif + thd->fatal_error(); + goto end; + } + + handle_bootstrap_impl(thd); + end: net_end(&thd->net); thd->cleanup(); @@ -550,7 +567,8 @@ end: my_thread_end(); pthread_exit(0); #endif - DBUG_RETURN(0); + + return 0; } @@ -1211,20 +1229,20 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { if (alloc_query(thd, packet, packet_length)) break; // fatal error is set - char *packet_end= thd->query + thd->query_length; + char *packet_end= thd->query() + thd->query_length(); /* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */ const char* end_of_stmt= NULL; - general_log_write(thd, command, thd->query, thd->query_length); - DBUG_PRINT("query",("%-.4096s",thd->query)); + general_log_write(thd, command, thd->query(), thd->query_length()); + DBUG_PRINT("query",("%-.4096s",thd->query())); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) - thd->profiling.set_query_source(thd->query, thd->query_length); + thd->profiling.set_query_source(thd->query(), thd->query_length()); #endif if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); - mysql_parse(thd, thd->query, thd->query_length, &end_of_stmt); + mysql_parse(thd, thd->query(), thd->query_length(), &end_of_stmt); while (!thd->killed && (end_of_stmt != NULL) && ! thd->is_error()) { @@ -1436,7 +1454,28 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (check_global_access(thd,RELOAD_ACL)) break; general_log_print(thd, command, NullS); - if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used)) +#ifndef DBUG_OFF + bool debug_simulate= FALSE; + DBUG_EXECUTE_IF("simulate_detached_thread_refresh", debug_simulate= TRUE;); + if (debug_simulate) + { + /* + Simulate a reload without a attached thread session. + Provides a environment similar to that of when the + server receives a SIGHUP signal and reloads caches + and flushes tables. + */ + bool res; + my_pthread_setspecific_ptr(THR_THD, NULL); + res= reload_acl_and_cache(NULL, options | REFRESH_FAST, + NULL, ¬_used); + my_pthread_setspecific_ptr(THR_THD, thd); + if (!res) + my_ok(thd); + break; + } +#endif + if (!reload_acl_and_cache(thd, options, NULL, ¬_used)) my_ok(thd); break; } @@ -1672,7 +1711,8 @@ void log_slow_statement(THD *thd) { thd_proc_info(thd, "logging slow query"); thd->status_var.long_query_count++; - slow_log_print(thd, thd->query, thd->query_length, end_utime_of_query); + slow_log_print(thd, thd->query(), thd->query_length(), + end_utime_of_query); } } DBUG_VOID_RETURN; @@ -2990,7 +3030,7 @@ end_with_restore_list: /* Presumably, REPAIR and binlog writing doesn't require synchronization */ - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } select_lex->table_list.first= (uchar*) first_table; lex->query_tables=all_tables; @@ -3024,7 +3064,7 @@ end_with_restore_list: /* Presumably, ANALYZE and binlog writing doesn't require synchronization */ - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } select_lex->table_list.first= (uchar*) first_table; lex->query_tables=all_tables; @@ -3048,7 +3088,7 @@ end_with_restore_list: /* Presumably, OPTIMIZE and binlog writing doesn't require synchronization */ - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } select_lex->table_list.first= (uchar*) first_table; lex->query_tables=all_tables; @@ -4000,7 +4040,7 @@ end_with_restore_list: */ if (!lex->no_write_to_binlog && write_to_binlog) { - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); } my_ok(thd); } @@ -4577,7 +4617,7 @@ create_sp_error: case SP_KEY_NOT_FOUND: if (lex->drop_if_exists) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), SP_COM_STRING(lex), lex->spname->m_name.str); @@ -5107,8 +5147,6 @@ bool check_single_table_access(THD *thd, ulong privilege, /* Show only 1 table for check_grant */ if (!(all_tables->belong_to_view && (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && - !(all_tables->view && - all_tables->effective_algorithm == VIEW_ALGORITHM_TMPTABLE) && check_grant(thd, privilege, all_tables, 0, 1, no_errors)) goto deny; @@ -5970,9 +6008,10 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, PROCESSLIST. Note that we don't need LOCK_thread_count to modify query_length. */ - if (*found_semicolon && - (thd->query_length= (ulong)(*found_semicolon - thd->query))) - thd->query_length--; + if (*found_semicolon && (ulong) (*found_semicolon - thd->query())) + thd->set_query_inner(thd->query(), + (uint32) (*found_semicolon - + thd->query() - 1)); /* Actually execute the query */ if (*found_semicolon) { @@ -6278,6 +6317,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->table_name_length=table->table.length; ptr->lock_type= lock_type; ptr->updating= test(table_options & TL_OPTION_UPDATING); + /* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */ ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX); ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES); ptr->derived= table->sel; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index f7453e76d21..2b589c0c1b2 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4077,7 +4077,7 @@ static int fast_end_partition(THD *thd, ulonglong copied, if ((!is_empty) && (!written_bin_log) && (!thd->lex->no_write_to_binlog)) - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO), (ulong) (copied + deleted), @@ -6235,7 +6235,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_5") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, - thd->query, thd->query_length), FALSE)) || + thd->query(), thd->query_length()), FALSE)) || ERROR_INJECT_CRASH("crash_drop_partition_6") || ((frm_install= TRUE), FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || @@ -6302,7 +6302,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_add_partition_5") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, - thd->query, thd->query_length), FALSE)) || + thd->query(), thd->query_length()), FALSE)) || ERROR_INJECT_CRASH("crash_add_partition_6") || write_log_rename_frm(lpt) || (not_completed= FALSE) || @@ -6392,7 +6392,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_6") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, - thd->query, thd->query_length), FALSE)) || + thd->query(), thd->query_length()), FALSE)) || ERROR_INJECT_CRASH("crash_change_partition_7") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ERROR_INJECT_CRASH("crash_change_partition_8") || @@ -7209,4 +7209,3 @@ void create_subpartition_name(char *out, const char *in1, "#SP#", transl_subpart_name, "#REN#", NullS); } #endif - diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index a5e65d11304..37e5a583840 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1536,7 +1536,7 @@ error: void plugin_shutdown(void) { - uint i, count= plugin_array.elements, free_slots= 0; + uint i, count= plugin_array.elements; struct st_plugin_int **plugins, *plugin; struct st_plugin_dl **dl; DBUG_ENTER("plugin_shutdown"); @@ -1557,18 +1557,13 @@ void plugin_shutdown(void) while (reap_needed && (count= plugin_array.elements)) { reap_plugins(); - for (i= free_slots= 0; i < count; i++) + for (i= 0; i < count; i++) { plugin= *dynamic_element(&plugin_array, i, struct st_plugin_int **); - switch (plugin->state) { - case PLUGIN_IS_READY: + if (plugin->state == PLUGIN_IS_READY) + { plugin->state= PLUGIN_IS_DELETED; reap_needed= true; - break; - case PLUGIN_IS_FREED: - case PLUGIN_IS_UNINITIALIZED: - free_slots++; - break; } } if (!reap_needed) @@ -1581,9 +1576,6 @@ void plugin_shutdown(void) } } - if (count > free_slots && global_system_variables.log_warnings > 1) - sql_print_warning("Forcing shutdown of %d plugins", count - free_slots); - plugins= (struct st_plugin_int **) my_alloca(sizeof(void*) * (count+1)); /* @@ -1605,8 +1597,8 @@ void plugin_shutdown(void) if (!(plugins[i]->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_FREED | PLUGIN_IS_DISABLED))) { - sql_print_information("Plugin '%s' will be forced to shutdown", - plugins[i]->name.str); + sql_print_warning("Plugin '%s' will be forced to shutdown", + plugins[i]->name.str); /* We are forcing deinit on plugins so we don't want to do a ref_count check until we have processed all the plugins. @@ -2090,7 +2082,7 @@ static int check_func_set(THD *thd, struct st_mysql_sys_var *var, const char *strvalue= "NULL", *str; TYPELIB *typelib; ulonglong result; - uint error_len; + uint error_len= 0; // init as only set on error bool not_used; int length; @@ -2689,7 +2681,9 @@ uchar* sys_var_pluginvar::value_ptr(THD *thd, enum_var_type type, { if (!(value & mask)) continue; - str.append(typelib->type_names[i], typelib->type_lengths[i]); + str.append(typelib->type_names[i], typelib->type_lengths + ? typelib->type_lengths[i] + : strlen(typelib->type_names[i])); str.append(','); } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 5fee201dcd2..ead31436dc7 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -752,7 +752,7 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array, const String *res; DBUG_ENTER("insert_params_with_log"); - if (query->copy(stmt->query, stmt->query_length, default_charset_info)) + if (query->copy(stmt->query(), stmt->query_length(), default_charset_info)) DBUG_RETURN(1); for (Item_param **it= begin; it < end; ++it) @@ -914,7 +914,7 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt, DBUG_ENTER("emb_insert_params_with_log"); - if (query->copy(stmt->query, stmt->query_length, default_charset_info)) + if (query->copy(stmt->query(), stmt->query_length(), default_charset_info)) DBUG_RETURN(1); for (; it < end; ++it, ++client_param) @@ -1065,7 +1065,7 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, DBUG_ENTER("insert_params_from_vars"); - if (query->copy(stmt->query, stmt->query_length, default_charset_info)) + if (query->copy(stmt->query(), stmt->query_length(), default_charset_info)) DBUG_RETURN(1); for (Item_param **it= begin; it < end; ++it) @@ -2346,6 +2346,9 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) /* Fix ORDER list */ for (order= (ORDER *)sl->order_list.first; order; order= order->next) order->item= &order->item_ptr; + + /* clear the no_error flag for INSERT/UPDATE IGNORE */ + sl->no_error= FALSE; } { SELECT_LEX_UNIT *unit= sl->master_unit(); @@ -2461,9 +2464,9 @@ void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length) } #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) - thd->profiling.set_query_source(stmt->query, stmt->query_length); + thd->profiling.set_query_source(stmt->query(), stmt->query_length()); #endif - DBUG_PRINT("exec_query", ("%s", stmt->query)); + DBUG_PRINT("exec_query", ("%s", stmt->query())); DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt)); sp_cache_flush_obsolete(&thd->sp_proc_cache); @@ -3032,7 +3035,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) old_stmt_arena= thd->stmt_arena; thd->stmt_arena= this; - Parser_state parser_state(thd, thd->query, thd->query_length); + Parser_state parser_state(thd, thd->query(), thd->query_length()); parser_state.m_lip.stmt_prepare_mode= TRUE; lex_start(thd); @@ -3121,7 +3124,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) the general log. */ if (thd->spcont == NULL) - general_log_write(thd, COM_STMT_PREPARE, query, query_length); + general_log_write(thd, COM_STMT_PREPARE, query(), query_length()); } DBUG_RETURN(error); } @@ -3312,7 +3315,7 @@ Prepared_statement::reprepare() return TRUE; error= ((name.str && copy.set_name(&name)) || - copy.prepare(query, query_length) || + copy.prepare(query(), query_length()) || validate_metadata(©)); if (cur_db_changed) @@ -3550,8 +3553,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) to point at it even after we restore from backup. This is ok, as expanded query was allocated in thd->mem_root. */ - stmt_backup.query= thd->query; - stmt_backup.query_length= thd->query_length; + stmt_backup.set_query_inner(thd->query(), thd->query_length()); /* At first execution of prepared statement we may perform logical @@ -3576,8 +3578,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) Note that multi-statements cannot exist here (they are not supported in prepared statements). */ - if (query_cache_send_result_to_client(thd, thd->query, - thd->query_length) <= 0) + if (query_cache_send_result_to_client(thd, thd->query(), + thd->query_length()) <= 0) { error= mysql_execute_command(thd); } @@ -3622,7 +3624,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) the general log. */ if (error == 0 && thd->spcont == NULL) - general_log_write(thd, COM_STMT_EXECUTE, thd->query, thd->query_length); + general_log_write(thd, COM_STMT_EXECUTE, thd->query(), thd->query_length()); error: flags&= ~ (uint) IS_IN_USE; diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 0e0b8eb60b9..dac96f2e9c4 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -177,7 +177,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) /* Lets hope this doesn't fail as the result will be messy */ if (!silent && !error) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); my_ok(thd); } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 06489d8bbd3..f05147d4146 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -623,7 +623,7 @@ impossible position"; */ { log.error=0; - bool read_packet = 0, fatal_error = 0; + bool read_packet = 0; #ifndef DBUG_OFF if (max_binlog_dump_events && !left_events--) @@ -645,7 +645,7 @@ impossible position"; */ pthread_mutex_lock(log_lock); - switch (Log_event::read_log_event(&log, packet, (pthread_mutex_t*)0)) { + switch (error= Log_event::read_log_event(&log, packet, (pthread_mutex_t*) 0)) { case 0: /* we read successfully, so we'll need to send it to the slave */ pthread_mutex_unlock(log_lock); @@ -671,8 +671,8 @@ impossible position"; default: pthread_mutex_unlock(log_lock); - fatal_error = 1; - break; + test_for_non_eof_log_read_errors(error, &errmsg); + goto err; } if (read_packet) @@ -701,12 +701,6 @@ impossible position"; */ } - if (fatal_error) - { - errmsg = "error reading log entry"; - my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; - goto err; - } log.error=0; } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 47af428ed56..30a91e882fe 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -159,6 +159,7 @@ static int join_read_const_table(JOIN_TAB *tab, POSITION *pos); static int join_read_system(JOIN_TAB *tab); static int join_read_const(JOIN_TAB *tab); static int join_read_key(JOIN_TAB *tab); +static void join_read_key_unlock_row(st_join_table *tab); static int join_read_always_key(JOIN_TAB *tab); static int join_read_last_key(JOIN_TAB *tab); static int join_no_more_records(READ_RECORD *info); @@ -643,6 +644,18 @@ JOIN::prepare(Item ***rref_pointer_array, MYF(0)); /* purecov: inspected */ goto err; /* purecov: inspected */ } + if (thd->lex->derived_tables) + { + my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", + thd->lex->derived_tables & DERIVED_VIEW ? + "view" : "subquery"); + goto err; + } + if (thd->lex->sql_command != SQLCOM_SELECT) + { + my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "non-SELECT"); + goto err; + } } if (!procedure && result && result->prepare(fields_list, unit_arg)) @@ -654,8 +667,11 @@ JOIN::prepare(Item ***rref_pointer_array, this->group= group_list != 0; unit= unit_arg; + if (tmp_table_param.sum_func_count && !group_list) + implicit_grouping= TRUE; + #ifdef RESTRICTED_GROUP - if (sum_func_count && !group_list && (func_count || field_count)) + if (implicit_grouping) { my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0)); goto err; @@ -891,15 +907,23 @@ JOIN::optimize() } #endif - /* Optimize count(*), min() and max() */ - if (tables_list && tmp_table_param.sum_func_count && ! group_list) + /* + Try to optimize count(*), min() and max() to const fields if + there is implicit grouping (aggregate functions but no + group_list). In this case, the result set shall only contain one + row. + */ + if (tables_list && implicit_grouping) { int res; /* opt_sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match to the WHERE conditions, - or 1 if all items were resolved, + or 1 if all items were resolved (optimized away), or 0, or an error number HA_ERR_... + + If all items were resolved by opt_sum_query, there is no need to + open any tables. */ if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds))) { @@ -968,6 +992,12 @@ JOIN::optimize() DBUG_RETURN(1); } + if (select_lex->olap == ROLLUP_TYPE && rollup_process_const_fields()) + { + DBUG_PRINT("error", ("Error: rollup_process_fields() failed")); + DBUG_RETURN(1); + } + /* Remove distinct if only const tables */ select_distinct= select_distinct && (const_tables != tables); thd_proc_info(thd, "preparing"); @@ -1098,7 +1128,7 @@ JOIN::optimize() join_tab[const_tables].select->quick->get_type() != QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)) { - if (group_list && + if (group_list && rollup.state == ROLLUP::STATE_NONE && list_contains_unique_index(join_tab[const_tables].table, find_field_in_order_list, (void *) group_list)) @@ -1142,7 +1172,8 @@ JOIN::optimize() if (! hidden_group_fields && rollup.state == ROLLUP::STATE_NONE) select_distinct=0; } - else if (select_distinct && tables - const_tables == 1) + else if (select_distinct && tables - const_tables == 1 && + rollup.state == ROLLUP::STATE_NONE) { /* We are only using one table. In this case we change DISTINCT to a @@ -1241,13 +1272,22 @@ JOIN::optimize() (!group_list && tmp_table_param.sum_func_count)) order=0; - // Can't use sort on head table if using row cache + // Can't use sort on head table if using join buffering if (full_join) { - if (group_list) - simple_group=0; - if (order) - simple_order=0; + TABLE *stable= (sort_by_table == (TABLE *) 1 ? + join_tab[const_tables].table : sort_by_table); + /* + FORCE INDEX FOR ORDER BY can be used to prevent join buffering when + sorting on the first table. + */ + if (!stable || !stable->force_index_order) + { + if (group_list) + simple_group= 0; + if (order) + simple_order= 0; + } } /* @@ -1533,12 +1573,8 @@ JOIN::optimize() } } - /* - If this join belongs to an uncacheable subquery save - the original join - */ - if (select_lex->uncacheable && !is_top_level_join() && - init_save_join_tab()) + /* If this join belongs to an uncacheable query save the original join */ + if (select_lex->uncacheable && init_save_join_tab()) DBUG_RETURN(-1); /* purecov: inspected */ } @@ -2039,7 +2075,8 @@ JOIN::exec() count_field_types(select_lex, &curr_join->tmp_table_param, *curr_all_fields, 0); - if (curr_join->group || curr_join->tmp_table_param.sum_func_count || + if (curr_join->group || curr_join->implicit_grouping || + curr_join->tmp_table_param.sum_func_count || (procedure && (procedure->flags & PROC_GROUP))) { if (make_group_fields(this, curr_join)) @@ -2274,7 +2311,7 @@ JOIN::destroy() tab->cleanup(); } tmp_join->tmp_join= 0; - tmp_table_param.copy_field=0; + tmp_table_param.copy_field= 0; DBUG_RETURN(tmp_join->destroy()); } cond_equal= 0; @@ -3379,12 +3416,12 @@ add_key_equal_fields(KEY_FIELD **key_fields, uint and_level, @retval FALSE it's something else */ -inline static bool +static bool is_local_field (Item *field) { - field= field->real_item(); - return field->type() == Item::FIELD_ITEM && - !((Item_field *)field)->depended_from; + return field->real_item()->type() == Item::FIELD_ITEM + && !(field->used_tables() & OUTER_REF_TABLE_BIT) + && !((Item_field *)field->real_item())->depended_from; } @@ -3629,7 +3666,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) { if (!(form->keys_in_use_for_query.is_set(key))) continue; - if (form->key_info[key].flags & HA_FULLTEXT) + if (form->key_info[key].flags & (HA_FULLTEXT | HA_SPATIAL)) continue; // ToDo: ft-keys in non-ft queries. SerG uint key_parts= (uint) form->key_info[key].key_parts; @@ -5677,7 +5714,9 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, } j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length); j->ref.key_err=1; + j->ref.has_record= FALSE; j->ref.null_rejecting= 0; + j->ref.use_count= 0; keyuse=org_keyuse; store_key **ref_key= j->ref.key_copy; @@ -6511,6 +6550,20 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) DBUG_RETURN(0); } + +/** + The default implementation of unlock-row method of READ_RECORD, + used in all access methods. +*/ + +void rr_unlock_row(st_join_table *tab) +{ + READ_RECORD *info= &tab->read_record; + info->file->unlock_row(); +} + + + static void make_join_readinfo(JOIN *join, ulonglong options) { @@ -6526,6 +6579,7 @@ make_join_readinfo(JOIN *join, ulonglong options) TABLE *table=tab->table; tab->read_record.table= table; tab->read_record.file=table->file; + tab->read_record.unlock_row= rr_unlock_row; tab->next_select=sub_select; /* normal select */ /* @@ -6571,6 +6625,7 @@ make_join_readinfo(JOIN *join, ulonglong options) delete tab->quick; tab->quick=0; tab->read_first_record= join_read_key; + tab->read_record.unlock_row= join_read_key_unlock_row; tab->read_record.read_record= join_no_more_records; if (table->covering_keys.is_set(tab->ref.key) && !table->no_keyread) @@ -9046,7 +9101,10 @@ static void restore_prev_nj_state(JOIN_TAB *last) join->cur_embedding_map&= ~last_emb->nested_join->nj_map; else if (last_emb->nested_join->n_tables-1 == last_emb->nested_join->counter) + { join->cur_embedding_map|= last_emb->nested_join->nj_map; + break; + } else break; last_emb= last_emb->embedding; @@ -9493,8 +9551,47 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, new_field->set_derivation(item->collation.derivation); break; case DECIMAL_RESULT: - new_field= Field_new_decimal::new_decimal_field(item); + { + uint8 dec= item->decimals; + uint8 intg= ((Item_decimal *) item)->decimal_precision() - dec; + uint32 len= item->max_length; + + /* + Trying to put too many digits overall in a DECIMAL(prec,dec) + will always throw a warning. We must limit dec to + DECIMAL_MAX_SCALE however to prevent an assert() later. + */ + + if (dec > 0) + { + signed int overflow; + + dec= min(dec, DECIMAL_MAX_SCALE); + + /* + If the value still overflows the field with the corrected dec, + we'll throw out decimals rather than integers. This is still + bad and of course throws a truncation warning. + +1: for decimal point + */ + + const int required_length= + my_decimal_precision_to_length(intg + dec, dec, + item->unsigned_flag); + + overflow= required_length - len; + + if (overflow > 0) + dec= max(0, dec - overflow); // too long, discard fract + else + /* Corrected value fits. */ + len= required_length; + } + + new_field= new Field_new_decimal(len, maybe_null, item->name, + dec, item->unsigned_flag); break; + } case ROW_RESULT: default: // This case should never be choosen @@ -10303,6 +10400,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, for (; cur_group ; cur_group= cur_group->next, key_part_info++) { Field *field=(*cur_group->item)->get_tmp_table_field(); + DBUG_ASSERT(field->table == table); bool maybe_null=(*cur_group->item)->maybe_null; key_part_info->null_bit=0; key_part_info->field= field; @@ -11062,6 +11160,12 @@ Next_select_func setup_end_select_func(JOIN *join) } else { + /* + Choose method for presenting result to user. Use end_send_group + if the query requires grouping (has a GROUP BY clause and/or one or + more aggregate functions). Use end_send if the query should not + be grouped. + */ if ((join->sort_and_group || (join->procedure && join->procedure->flags & PROC_GROUP)) && !tmp_tbl->precomputed_group_by) @@ -11430,6 +11534,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, bool not_used_in_distinct=join_tab->not_used_in_distinct; ha_rows found_records=join->found_records; COND *select_cond= join_tab->select_cond; + bool select_cond_result= TRUE; if (error > 0 || (join->thd->is_error())) // Fatal error return NESTED_LOOP_ERROR; @@ -11441,7 +11546,17 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, return NESTED_LOOP_KILLED; /* purecov: inspected */ } DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond)); - if (!select_cond || select_cond->val_int()) + + if (select_cond) + { + select_cond_result= test(select_cond->val_int()); + + /* check for errors evaluating the condition */ + if (join->thd->is_error()) + return NESTED_LOOP_ERROR; + } + + if (!select_cond || select_cond_result) { /* There is no select condition or the attached pushed down @@ -11525,7 +11640,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, return NESTED_LOOP_NO_MORE_ROWS; } else - join_tab->read_record.file->unlock_row(); + join_tab->read_record.unlock_row(join_tab); } else { @@ -11535,7 +11650,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, */ join->examined_rows++; join->thd->row_count++; - join_tab->read_record.file->unlock_row(); + join_tab->read_record.unlock_row(join_tab); } return NESTED_LOOP_OK; } @@ -11915,18 +12030,55 @@ join_read_key(JOIN_TAB *tab) table->status=STATUS_NOT_FOUND; return -1; } + /* + Moving away from the current record. Unlock the row + in the handler if it did not match the partial WHERE. + */ + if (tab->ref.has_record && tab->ref.use_count == 0) + { + tab->read_record.file->unlock_row(); + tab->ref.has_record= FALSE; + } error=table->file->index_read_map(table->record[0], tab->ref.key_buff, make_prev_keypart_map(tab->ref.key_parts), HA_READ_KEY_EXACT); if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) return report_error(table, error); + + if (! error) + { + tab->ref.has_record= TRUE; + tab->ref.use_count= 1; + } + } + else if (table->status == 0) + { + DBUG_ASSERT(tab->ref.has_record); + tab->ref.use_count++; } table->null_row=0; return table->status ? -1 : 0; } +/** + Since join_read_key may buffer a record, do not unlock + it if it was not used in this invocation of join_read_key(). + Only count locks, thus remembering if the record was left unused, + and unlock already when pruning the current value of + TABLE_REF buffer. + @sa join_read_key() +*/ + +static void +join_read_key_unlock_row(st_join_table *tab) +{ + DBUG_ASSERT(tab->ref.use_count); + if (tab->ref.use_count) + tab->ref.use_count--; +} + /* ref access method implementation: "read_first" function @@ -13994,7 +14146,10 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, if (error) { if (error == HA_ERR_RECORD_DELETED) - continue; + { + error= file->rnd_next(record); + continue; + } if (error == HA_ERR_END_OF_FILE) break; goto err; @@ -15923,32 +16078,7 @@ bool JOIN::rollup_init() { item->maybe_null= 1; found_in_group= 1; - if (item->const_item()) - { - /* - For ROLLUP queries each constant item referenced in GROUP BY list - is wrapped up into an Item_func object yielding the same value - as the constant item. The objects of the wrapper class are never - considered as constant items and besides they inherit all - properties of the Item_result_field class. - This wrapping allows us to ensure writing constant items - into temporary tables whenever the result of the ROLLUP - operation has to be written into a temporary table, e.g. when - ROLLUP is used together with DISTINCT in the SELECT list. - Usually when creating temporary tables for a intermidiate - result we do not include fields for constant expressions. - */ - Item* new_item= new Item_func_rollup_const(item); - if (!new_item) - return 1; - new_item->fix_fields(thd, (Item **) 0); - thd->change_item_tree(it.ref(), new_item); - for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next) - { - if (*tmp->item == item) - thd->change_item_tree(tmp->item, new_item); - } - } + break; } } if (item->type() == Item::FUNC_ITEM && !found_in_group) @@ -15967,6 +16097,59 @@ bool JOIN::rollup_init() } return 0; } + +/** + Wrap all constant Items in GROUP BY list. + + For ROLLUP queries each constant item referenced in GROUP BY list + is wrapped up into an Item_func object yielding the same value + as the constant item. The objects of the wrapper class are never + considered as constant items and besides they inherit all + properties of the Item_result_field class. + This wrapping allows us to ensure writing constant items + into temporary tables whenever the result of the ROLLUP + operation has to be written into a temporary table, e.g. when + ROLLUP is used together with DISTINCT in the SELECT list. + Usually when creating temporary tables for a intermidiate + result we do not include fields for constant expressions. + + @retval + 0 if ok + @retval + 1 on error +*/ + +bool JOIN::rollup_process_const_fields() +{ + ORDER *group_tmp; + Item *item; + List_iterator<Item> it(all_fields); + + for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next) + { + if (!(*group_tmp->item)->const_item()) + continue; + while ((item= it++)) + { + if (*group_tmp->item == item) + { + Item* new_item= new Item_func_rollup_const(item); + if (!new_item) + return 1; + new_item->fix_fields(thd, (Item **) 0); + thd->change_item_tree(it.ref(), new_item); + for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next) + { + if (*tmp->item == item) + thd->change_item_tree(tmp->item, new_item); + } + break; + } + } + it.rewind(); + } + return 0; +} /** diff --git a/sql/sql_select.h b/sql/sql_select.h index 271c88ebf66..d8f1769397c 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -58,6 +58,8 @@ class store_key; typedef struct st_table_ref { bool key_err; + /** True if something was read into buffer in join_read_key. */ + bool has_record; uint key_parts; ///< num of ... uint key_length; ///< length of key_buff int key; ///< key no @@ -85,6 +87,11 @@ typedef struct st_table_ref table_map depend_map; ///< Table depends on these tables. /* null byte position in the key_buf. Used for REF_OR_NULL optimization */ uchar *null_ref_key; + /* + The number of times the record associated with this key was used + in the join. + */ + ha_rows use_count; } TABLE_REF; @@ -278,7 +285,14 @@ public: TABLE **table,**all_tables,*sort_by_table; uint tables,const_tables; uint send_group_parts; - bool sort_and_group,first_record,full_join,group, no_field_update; + /** + Indicates that grouping will be performed on the result set during + query execution. This field belongs to query execution. + + @see make_group_fields, alloc_group_fields, JOIN::exec + */ + bool sort_and_group; + bool first_record,full_join,group, no_field_update; bool do_send_rows; /** TRUE when we want to resume nested loop iterations when @@ -365,6 +379,8 @@ public: simple_xxxxx is set if ORDER/GROUP BY doesn't include any references to other tables than the first non-constant table in the JOIN. It's also set if ORDER/GROUP BY is empty. + Used for deciding for or against using a temporary table to compute + GROUP/ORDER BY. */ bool simple_order, simple_group; /** @@ -435,6 +451,7 @@ public: const_tables= 0; eliminated_tables= 0; join_list= 0; + implicit_grouping= FALSE; sort_and_group= 0; first_record= 0; do_send_rows= 1; @@ -511,6 +528,7 @@ public: } bool rollup_init(); + bool rollup_process_const_fields(); bool rollup_make_fields(List<Item> &all_fields, List<Item> &fields, Item_sum ***func); int rollup_send_data(uint idx); @@ -544,6 +562,11 @@ public: return (table_map(1) << tables) - 1; } private: + /** + TRUE if the query contains an aggregate function but has no GROUP + BY clause. + */ + bool implicit_grouping; bool make_simple_join(JOIN *join, TABLE *tmp_table); }; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 0601aa976b8..37c12739566 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -583,6 +583,126 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, } +/** + An Internal_error_handler that suppresses errors regarding views' + underlying tables that occur during privilege checking within SHOW CREATE + VIEW commands. This happens in the cases when + + - A view's underlying table (e.g. referenced in its SELECT list) does not + exist. There should not be an error as no attempt was made to access it + per se. + + - Access is denied for some table, column, function or stored procedure + such as mentioned above. This error gets raised automatically, since we + can't untangle its access checking from that of the view itself. + */ +class Show_create_error_handler : public Internal_error_handler { + + TABLE_LIST *m_top_view; + bool m_handling; + Security_context *m_sctx; + + char m_view_access_denied_message[MYSQL_ERRMSG_SIZE]; + char *m_view_access_denied_message_ptr; + +public: + + /** + Creates a new Show_create_error_handler for the particular security + context and view. + + @thd Thread context, used for security context information if needed. + @top_view The view. We do not verify at this point that top_view is in + fact a view since, alas, these things do not stay constant. + */ + explicit Show_create_error_handler(THD *thd, TABLE_LIST *top_view) : + m_top_view(top_view), m_handling(FALSE), + m_view_access_denied_message_ptr(NULL) + { + + m_sctx = test(m_top_view->security_ctx) ? + m_top_view->security_ctx : thd->security_ctx; + } + + /** + Lazy instantiation of 'view access denied' message. The purpose of the + Show_create_error_handler is to hide details of underlying tables for + which we have no privileges behind ER_VIEW_INVALID messages. But this + obviously does not apply if we lack privileges on the view itself. + Unfortunately the information about for which table privilege checking + failed is not available at this point. The only way for us to check is by + reconstructing the actual error message and see if it's the same. + */ + char* get_view_access_denied_message() + { + if (!m_view_access_denied_message_ptr) + { + m_view_access_denied_message_ptr= m_view_access_denied_message; + my_snprintf(m_view_access_denied_message, MYSQL_ERRMSG_SIZE, + ER(ER_TABLEACCESS_DENIED_ERROR), "SHOW VIEW", + m_sctx->priv_user, + m_sctx->host_or_ip, m_top_view->get_table_name()); + } + return m_view_access_denied_message_ptr; + } + + bool handle_error(uint sql_errno, const char *message, + MYSQL_ERROR::enum_warning_level level, THD *thd) { + /* + The handler does not handle the errors raised by itself. + At this point we know if top_view is really a view. + */ + if (m_handling || !m_top_view->view) + return FALSE; + + m_handling= TRUE; + + bool is_handled; + + switch (sql_errno) + { + case ER_TABLEACCESS_DENIED_ERROR: + if (!strcmp(get_view_access_denied_message(), message)) + { + /* Access to top view is not granted, don't interfere. */ + is_handled= FALSE; + break; + } + case ER_COLUMNACCESS_DENIED_ERROR: + case ER_VIEW_NO_EXPLAIN: /* Error was anonymized, ignore all the same. */ + case ER_PROCACCESS_DENIED_ERROR: + is_handled= TRUE; + break; + + case ER_NO_SUCH_TABLE: + /* Established behavior: warn if underlying tables are missing. */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_VIEW_INVALID, + ER(ER_VIEW_INVALID), + m_top_view->get_db_name(), + m_top_view->get_table_name()); + is_handled= TRUE; + break; + + case ER_SP_DOES_NOT_EXIST: + /* Established behavior: warn if underlying functions are missing. */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_VIEW_INVALID, + ER(ER_VIEW_INVALID), + m_top_view->get_db_name(), + m_top_view->get_table_name()); + is_handled= TRUE; + break; + default: + is_handled= FALSE; + } + + m_handling= FALSE; + return is_handled; + } +}; + + bool mysqld_show_create(THD *thd, TABLE_LIST *table_list) { @@ -596,26 +716,13 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) /* We want to preserve the tree for views. */ thd->lex->view_prepare_mode= TRUE; - /* Only one table for now, but VIEW can involve several tables */ - if (open_normal_and_derived_tables(thd, table_list, 0)) { - if (!table_list->view || - (thd->is_error() && thd->main_da.sql_errno() != ER_VIEW_INVALID)) + Show_create_error_handler view_error_suppressor(thd, table_list); + thd->push_internal_handler(&view_error_suppressor); + bool error= open_normal_and_derived_tables(thd, table_list, 0); + thd->pop_internal_handler(); + if (error && thd->main_da.is_error()) DBUG_RETURN(TRUE); - - /* - Clear all messages with 'error' level status and - issue a warning with 'warning' level status in - case of invalid view and last error is ER_VIEW_INVALID - */ - mysql_reset_errors(thd, true); - thd->clear_error(); - - push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN, - ER_VIEW_INVALID, - ER(ER_VIEW_INVALID), - table_list->view_db.str, - table_list->view_name.str); } /* TODO: add environment variables show when it become possible */ @@ -1771,15 +1878,10 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) thd_info->query=0; /* Lock THD mutex that protects its data when looking at it. */ pthread_mutex_lock(&tmp->LOCK_thd_data); - if (tmp->query) + if (tmp->query()) { - /* - query_length is always set to 0 when we set query = NULL; see - the comment in sql_class.h why this prevents crashes in possible - races with query_length - */ - uint length= min(max_query_length, tmp->query_length); - thd_info->query=(char*) thd->strmake(tmp->query,length); + uint length= min(max_query_length, tmp->query_length()); + thd_info->query= (char*) thd->strmake(tmp->query(),length); } pthread_mutex_unlock(&tmp->LOCK_thd_data); thread_infos.append(thd_info); @@ -1892,7 +1994,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) tmp->mysys_var->current_cond ? "Waiting on cond" : NullS); #else - val= (char *) "Writing to net"; + val= (char *) (tmp->proc_info ? tmp->proc_info : NullS); #endif if (val) { @@ -1904,11 +2006,11 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) pthread_mutex_unlock(&mysys_var->mutex); /* INFO */ - if (tmp->query) + if (tmp->query()) { - table->field[7]->store(tmp->query, + table->field[7]->store(tmp->query(), min(PROCESS_LIST_INFO_WIDTH, - tmp->query_length), cs); + tmp->query_length()), cs); table->field[7]->set_notnull(); } @@ -3549,7 +3651,9 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, TABLE_SHARE *share= show_table->s; handler *file= show_table->file; handlerton *tmp_db_type= share->db_type(); +#ifdef WITH_PARTITION_STORAGE_ENGINE bool is_partitioned= FALSE; +#endif if (share->tmp_table == SYSTEM_TMP_TABLE) table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs); else if (share->tmp_table) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 843e8db91ce..9cd16e51119 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -70,15 +70,21 @@ static void wait_for_kill_signal(THD *thd) /** @brief Helper function for explain_filename + @param thd Thread handle + @param to_p Explained name in system_charset_info + @param end_p End of the to_p buffer + @param name Name to be converted + @param name_len Length of the name, in bytes */ -static char* add_identifier(char *to_p, const char * end_p, - const char* name, uint name_len, bool add_quotes) +static char* add_identifier(THD* thd, char *to_p, const char * end_p, + const char* name, uint name_len) { uint res; uint errors; const char *conv_name; char tmp_name[FN_REFLEN]; char conv_string[FN_REFLEN]; + int quote; DBUG_ENTER("add_identifier"); if (!name[name_len]) @@ -102,19 +108,21 @@ static char* add_identifier(char *to_p, const char * end_p, conv_name= conv_string; } - if (add_quotes && (end_p - to_p > 2)) + quote = thd ? get_quote_char_for_identifier(thd, conv_name, res - 1) : '"'; + + if (quote != EOF && (end_p - to_p > 2)) { - *(to_p++)= '`'; + *(to_p++)= (char) quote; while (*conv_name && (end_p - to_p - 1) > 0) { uint length= my_mbcharlen(system_charset_info, *conv_name); if (!length) length= 1; - if (length == 1 && *conv_name == '`') + if (length == 1 && *conv_name == (char) quote) { if ((end_p - to_p) < 3) break; - *(to_p++)= '`'; + *(to_p++)= (char) quote; *(to_p++)= *(conv_name++); } else if (((long) length) < (end_p - to_p)) @@ -125,7 +133,11 @@ static char* add_identifier(char *to_p, const char * end_p, else break; /* string already filled */ } - to_p= strnmov(to_p, "`", end_p - to_p); + if (end_p > to_p) { + *(to_p++)= (char) quote; + if (end_p > to_p) + *to_p= 0; /* terminate by NUL, but do not include it in the count */ + } } else to_p= strnmov(to_p, conv_name, end_p - to_p); @@ -145,6 +157,7 @@ static char* add_identifier(char *to_p, const char * end_p, diagnostic, error etc. when it would be useful to know what a particular file [and directory] means. Such as SHOW ENGINE STATUS, error messages etc. + @param thd Thread handle @param from Path name in my_charset_filename Null terminated in my_charset_filename, normalized to use '/' as directory separation character. @@ -161,13 +174,12 @@ static char* add_identifier(char *to_p, const char * end_p, [,[ Temporary| Renamed] Partition `p` [, Subpartition `sp`]] *| (| is really a /, and it is all in one line) - EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING -> - same as above but no quotes are added. @retval Length of returned string */ -uint explain_filename(const char *from, +uint explain_filename(THD* thd, + const char *from, char *to, uint to_length, enum_explain_filename_mode explain_mode) @@ -281,14 +293,12 @@ uint explain_filename(const char *from, { to_p= strnmov(to_p, ER(ER_DATABASE_NAME), end_p - to_p); *(to_p++)= ' '; - to_p= add_identifier(to_p, end_p, db_name, db_name_len, 1); + to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len); to_p= strnmov(to_p, ", ", end_p - to_p); } else { - to_p= add_identifier(to_p, end_p, db_name, db_name_len, - (explain_mode != - EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); + to_p= add_identifier(thd, to_p, end_p, db_name, db_name_len); to_p= strnmov(to_p, ".", end_p - to_p); } } @@ -296,16 +306,13 @@ uint explain_filename(const char *from, { to_p= strnmov(to_p, ER(ER_TABLE_NAME), end_p - to_p); *(to_p++)= ' '; - to_p= add_identifier(to_p, end_p, table_name, table_name_len, 1); + to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len); } else - to_p= add_identifier(to_p, end_p, table_name, table_name_len, - (explain_mode != - EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); + to_p= add_identifier(thd, to_p, end_p, table_name, table_name_len); if (part_name) { - if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT || - explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING) + if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT) to_p= strnmov(to_p, " /* ", end_p - to_p); else if (explain_mode == EXPLAIN_PARTITIONS_VERBOSE) to_p= strnmov(to_p, " ", end_p - to_p); @@ -321,20 +328,15 @@ uint explain_filename(const char *from, } to_p= strnmov(to_p, ER(ER_PARTITION_NAME), end_p - to_p); *(to_p++)= ' '; - to_p= add_identifier(to_p, end_p, part_name, part_name_len, - (explain_mode != - EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); + to_p= add_identifier(thd, to_p, end_p, part_name, part_name_len); if (subpart_name) { to_p= strnmov(to_p, ", ", end_p - to_p); to_p= strnmov(to_p, ER(ER_SUBPARTITION_NAME), end_p - to_p); *(to_p++)= ' '; - to_p= add_identifier(to_p, end_p, subpart_name, subpart_name_len, - (explain_mode != - EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); + to_p= add_identifier(thd, to_p, end_p, subpart_name, subpart_name_len); } - if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT || - explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING) + if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT) to_p= strnmov(to_p, " */", end_p - to_p); } DBUG_PRINT("exit", ("to '%s'", to)); @@ -1772,6 +1774,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, my_bool drop_temporary) { bool error= FALSE, need_start_waiters= FALSE; + Drop_table_error_handler err_handler(thd->get_internal_handler()); DBUG_ENTER("mysql_rm_table"); /* mark for close and remove all cached entries */ @@ -1792,7 +1795,10 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, LOCK_open during wait_if_global_read_lock(), other threads could not close their tables. This would make a pretty deadlock. */ + thd->push_internal_handler(&err_handler); error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0); + thd->pop_internal_handler(); + if (need_start_waiters) start_waiting_global_read_lock(thd); @@ -1894,9 +1900,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, DBUG_RETURN(1); } - /* Don't give warnings for not found errors, as we already generate notes */ - thd->no_warnings_for_error= 1; - for (table= tables; table; table= table->next_local) { char *db=table->db; @@ -1948,7 +1951,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, being built. The string always end in a comma and the comma will be chopped off before being written to the binary log. */ - if (thd->current_stmt_binlog_row_based && !dont_log_query) + if (!drop_temporary && thd->current_stmt_binlog_row_based && !dont_log_query) { non_temp_tables_count++; /* @@ -2086,7 +2089,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, tables). In this case, we can write the original query into the binary log. */ - write_bin_log(thd, !error, thd->query, thd->query_length); + write_bin_log(thd, !error, thd->query(), thd->query_length()); } else if (thd->current_stmt_binlog_row_based && tmp_table_deleted) @@ -2145,7 +2148,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, err_with_placeholders: unlock_table_names(thd, tables, (TABLE_LIST*) 0); pthread_mutex_unlock(&LOCK_open); - thd->no_warnings_for_error= 0; DBUG_RETURN(error); } @@ -3552,7 +3554,7 @@ static inline void write_create_table_bin_log(THD *thd, (!thd->current_stmt_binlog_row_based || (thd->current_stmt_binlog_row_based && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)))) - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } @@ -5226,6 +5228,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, char tmp_path[FN_REFLEN]; #endif char ts_name[FN_LEN + 1]; + myf flags= MY_DONT_OVERWRITE_FILE; DBUG_ENTER("mysql_create_like_table"); @@ -5282,8 +5285,12 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, DBUG_EXECUTE_IF("sleep_create_like_before_copy", my_sleep(6000000);); + if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) + flags|= MY_SYNC; + /* Create a new table by copying from source table + and sync the new table if the flag MY_SYNC is set Altough exclusive name-lock on target table protects us from concurrent DML and DDL operations on it we still want to wrap .FRM creation and call @@ -5304,7 +5311,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, goto err; } } - else if (my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE))) + else if (my_copy(src_path, dst_path, flags)) { if (my_errno == ENOENT) my_error(ER_BAD_DB_ERROR,MYF(0),db); @@ -5429,14 +5436,14 @@ binlog: write_bin_log(thd, TRUE, query.ptr(), query.length()); } else // Case 1 - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } /* Case 3 and 4 does nothing under RBR */ } else - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); res= FALSE; @@ -5524,7 +5531,7 @@ mysql_discard_or_import_tablespace(THD *thd, error=1; if (error) goto err; - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); err: ha_autocommit_or_rollback(thd, error); @@ -6550,7 +6557,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, + Query_log_event qinfo(thd, thd->query(), thd->query_length(), 0, FALSE, 0); mysql_bin_log.write(&qinfo); } @@ -6677,10 +6684,21 @@ view_err: goto err; } + /* + If this is an ALTER TABLE and no explicit row type specified reuse + the table's row type. + Note: this is the same as if the row type was specified explicitly and + we must thus set HA_CREATE_USED_ROW_FORMAT! + */ if (create_info->row_type == ROW_TYPE_NOT_USED) { + /* ALTER TABLE without explicit row type */ create_info->row_type= table->s->row_type; - create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT; + /* + We have to mark the row type as used, as otherwise the engine may + change the row format in update_create_info(). + */ + create_info->used_fields|= HA_CREATE_USED_ROW_FORMAT; } DBUG_PRINT("info", ("old type: %s new type: %s", @@ -6794,7 +6812,7 @@ view_err: if (!error) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); my_ok(thd); } else if (error > 0) @@ -7210,14 +7228,18 @@ view_err: /* Add the indexes. */ if ((error= table->file->add_index(table, key_info, index_add_count))) { - /* - Exchange the key_info for the error message. If we exchange - key number by key name in the message later, we need correct info. - */ - KEY *save_key_info= table->key_info; - table->key_info= key_info; - table->file->print_error(error, MYF(0)); - table->key_info= save_key_info; + /* Only report error if handler has not already reported an error */ + if (!thd->main_da.is_error()) + { + /* + Exchange the key_info for the error message. If we exchange + key number by key name in the message later, we need correct info. + */ + KEY *save_key_info= table->key_info; + table->key_info= key_info; + table->file->print_error(error, MYF(0)); + table->key_info= save_key_info; + } goto err1; } } @@ -7283,7 +7305,7 @@ view_err: goto err1; /* We don't replicate alter table statement on temporary tables */ if (!thd->current_stmt_binlog_row_based) - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); goto end_temporary; } @@ -7440,13 +7462,13 @@ view_err: DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000);); ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), db, table_name); DBUG_ASSERT(!(mysql_bin_log.is_open() && thd->current_stmt_binlog_row_based && (create_info->options & HA_LEX_CREATE_TMP_TABLE))); - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME)) { @@ -7912,10 +7934,11 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, for (uint i= 0; i < t->s->fields; i++ ) { Field *f= t->field[i]; + enum_field_types field_type= f->type(); + if (! thd->variables.old_mode && f->is_real_null(0)) continue; - enum_field_types field_type= f->type(); /* BLOB and VARCHAR have pointers in their field, we must convert to string; GEOMETRY is implemented on top of BLOB. diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc index 14b29452750..aec54bda13e 100644 --- a/sql/sql_tablespace.cc +++ b/sql/sql_tablespace.cc @@ -67,6 +67,6 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info) hton_name(hton)->str, "TABLESPACE or LOGFILE GROUP"); } - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); DBUG_RETURN(FALSE); } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index c055268ecca..a251a533622 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -409,7 +409,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) */ result= FALSE; /* Still, we need to log the query ... */ - stmt_query.append(thd->query, thd->query_length); + stmt_query.append(thd->query(), thd->query_length()); goto end; } } @@ -918,7 +918,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables, List_iterator<LEX_STRING> it_connection_cl_name(connection_cl_names); List_iterator<LEX_STRING> it_db_cl_name(db_cl_names); - stmt_query->append(thd->query, thd->query_length); + stmt_query->append(thd->query(), thd->query_length()); while ((name= it_name++)) { diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index c60dac42fb8..c6b41b59a3f 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -506,7 +506,7 @@ int mysql_create_function(THD *thd,udf_func *udf) rw_unlock(&THR_LOCK_udf); /* Binlog the create function. */ - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); DBUG_RETURN(0); @@ -581,7 +581,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) rw_unlock(&THR_LOCK_udf); /* Binlog the drop function. */ - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); DBUG_RETURN(0); err: diff --git a/sql/sql_update.cc b/sql/sql_update.cc index a721a086b6b..00769d2abda 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -810,7 +810,7 @@ int mysql_update(THD *thd, errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); if (thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), transactional_table, FALSE, errcode)) { error=1; // Rollback update @@ -1696,6 +1696,11 @@ bool multi_update::send_data(List<Item> ¬_used_values) TRG_EVENT_UPDATE)) DBUG_RETURN(1); + /* + Reset the table->auto_increment_field_not_null as it is valid for + only one row. + */ + table->auto_increment_field_not_null= FALSE; found++; if (!can_compare_record || compare_record(table)) { @@ -1860,7 +1865,7 @@ void multi_update::abort() */ int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), transactional_tables, FALSE, errcode); } thd->transaction.all.modified_non_trans_table= TRUE; @@ -2093,7 +2098,7 @@ bool multi_update::send_eof() else errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); if (thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), transactional_tables, FALSE, errcode)) { local_error= 1; // Rollback update diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 43d0b9fade0..ae3af0640a3 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1652,7 +1652,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) /* if something goes wrong, bin-log with possible error code, otherwise bin-log with error code cleared. */ - write_bin_log(thd, !something_wrong, thd->query, thd->query_length); + write_bin_log(thd, !something_wrong, thd->query(), thd->query_length()); } VOID(pthread_mutex_unlock(&LOCK_open)); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7064bac2085..c9a08200479 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7937,7 +7937,13 @@ udf_expr: $2->is_autogenerated_name= FALSE; $2->set_name($4.str, $4.length, system_charset_info); } - else + /* + A field has to have its proper name in order for name + resolution to work, something we are only guaranteed if we + parse it out. If we hijack the input stream with + remember_name we may get quoted or escaped names. + */ + else if ($2->type() != Item::FIELD_ITEM) $2->set_name($1, (uint) ($3 - $1), YYTHD->charset()); $$= $2; } @@ -9097,8 +9103,7 @@ procedure_clause: MYSQL_YYABORT; } - if (&lex->select_lex != lex->current_select || - lex->select_lex.get_table_list()->derived) + if (&lex->select_lex != lex->current_select) { my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery"); MYSQL_YYABORT; @@ -10440,14 +10445,12 @@ load: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= YYLIP; if (lex->sphead) { my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD DATA"); MYSQL_YYABORT; } - lex->fname_start= lip->get_ptr(); } load_data {} @@ -10479,14 +10482,10 @@ load_data: if (!(lex->exchange= new sql_exchange($4.str, 0))) MYSQL_YYABORT; } - opt_duplicate INTO - { - Lex->fname_end= YYLIP->get_ptr(); - } - TABLE_SYM table_ident + opt_duplicate INTO TABLE_SYM table_ident { LEX *lex=Lex; - if (!Select->add_table_to_list(YYTHD, $10, NULL, TL_OPTION_UPDATING, + if (!Select->add_table_to_list(YYTHD, $9, NULL, TL_OPTION_UPDATING, lex->lock_option)) MYSQL_YYABORT; lex->field_list.empty(); @@ -10494,7 +10493,7 @@ load_data: lex->value_list.empty(); } opt_load_data_charset - { Lex->exchange->cs= $12; } + { Lex->exchange->cs= $11; } opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec opt_load_data_set_spec {} @@ -10745,7 +10744,7 @@ param_marker: my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); MYSQL_YYABORT; } - item= new (thd->mem_root) Item_param((uint) (lip->get_tok_start() - thd->query)); + item= new (thd->mem_root) Item_param((uint) (lip->get_tok_start() - thd->query())); if (!($$= item) || lex->param_list.push_back(item)) { my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); diff --git a/sql/structs.h b/sql/structs.h index a58c18f97c5..2546d241059 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -115,16 +115,22 @@ typedef struct st_reginfo { /* Extra info about reg */ } REGINFO; -struct st_read_record; /* For referense later */ class SQL_SELECT; class THD; class handler; +struct st_join_table; + +void rr_unlock_row(st_join_table *tab); -typedef struct st_read_record { /* Parameter to read_record */ +struct READ_RECORD { /* Parameter to read_record */ + typedef int (*Read_func)(READ_RECORD*); + typedef void (*Unlock_row_func)(st_join_table *); struct st_table *table; /* Head-form */ handler *file; struct st_table **forms; /* head and ref forms */ - int (*read_record)(struct st_read_record *); + + Read_func read_record; + Unlock_row_func unlock_row; THD *thd; SQL_SELECT *select; uint cache_records; @@ -136,7 +142,7 @@ typedef struct st_read_record { /* Parameter to read_record */ uchar *cache,*cache_pos,*cache_end,*read_positions; IO_CACHE *io_cache; bool print_error, ignore_not_found_rows; -} READ_RECORD; +}; /* diff --git a/sql/table.cc b/sql/table.cc index 2c45dc800f5..e7fa0b2b2b0 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3338,7 +3338,12 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type) /** - Hide errors which show view underlying table information + Hide errors which show view underlying table information. + There are currently two mechanisms at work that handle errors for views, + this one and a more general mechanism based on an Internal_error_handler, + see Show_create_error_handler. The latter handles errors encountered during + execution of SHOW CREATE VIEW, while the machanism using this method is + handles SELECT from views. The two methods should not clash. @param[in,out] thd thread handler @@ -3347,6 +3352,8 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type) void TABLE_LIST::hide_view_error(THD *thd) { + if (thd->get_internal_handler()) + return; /* Hide "Unknown column" or "Unknown function" error */ DBUG_ASSERT(thd->is_error()); @@ -4630,7 +4637,8 @@ Item_subselect *TABLE_LIST::containing_subselect() (TABLE_LIST::index_hints). Using the information in this tagged list this function sets the members st_table::keys_in_use_for_query, st_table::keys_in_use_for_group_by, st_table::keys_in_use_for_order_by, - st_table::force_index and st_table::covering_keys. + st_table::force_index, st_table::force_index_order, + st_table::force_index_group and st_table::covering_keys. Current implementation of the runtime does not allow mixing FORCE INDEX and USE INDEX, so this is checked here. Then the FORCE INDEX list @@ -4758,14 +4766,28 @@ bool TABLE_LIST::process_index_hints(TABLE *tbl) } /* process FORCE INDEX as USE INDEX with a flag */ + if (!index_order[INDEX_HINT_FORCE].is_clear_all()) + { + tbl->force_index_order= TRUE; + index_order[INDEX_HINT_USE].merge(index_order[INDEX_HINT_FORCE]); + } + + if (!index_group[INDEX_HINT_FORCE].is_clear_all()) + { + tbl->force_index_group= TRUE; + index_group[INDEX_HINT_USE].merge(index_group[INDEX_HINT_FORCE]); + } + + /* + TODO: get rid of tbl->force_index (on if any FORCE INDEX is specified) and + create tbl->force_index_join instead. + Then use the correct force_index_XX instead of the global one. + */ if (!index_join[INDEX_HINT_FORCE].is_clear_all() || - !index_order[INDEX_HINT_FORCE].is_clear_all() || - !index_group[INDEX_HINT_FORCE].is_clear_all()) + tbl->force_index_group || tbl->force_index_order) { tbl->force_index= TRUE; index_join[INDEX_HINT_USE].merge(index_join[INDEX_HINT_FORCE]); - index_order[INDEX_HINT_USE].merge(index_order[INDEX_HINT_FORCE]); - index_group[INDEX_HINT_USE].merge(index_group[INDEX_HINT_FORCE]); } /* apply USE INDEX */ diff --git a/sql/table.h b/sql/table.h index a7ae50b8e72..acf1d797b69 100644 --- a/sql/table.h +++ b/sql/table.h @@ -754,6 +754,18 @@ struct st_table { bytes, it would take up 4. */ my_bool force_index; + + /** + Flag set when the statement contains FORCE INDEX FOR ORDER BY + See TABLE_LIST::process_index_hints(). + */ + my_bool force_index_order; + + /** + Flag set when the statement contains FORCE INDEX FOR GROUP BY + See TABLE_LIST::process_index_hints(). + */ + my_bool force_index_group; my_bool distinct,const_table,no_rows; /** diff --git a/sql/time.cc b/sql/time.cc index 44672eb4278..c4f6c3c9539 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -965,20 +965,22 @@ calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign, longlong *s 0 - a == b 1 - a > b - NOTES - TIME.second_part is not considered during comparison */ -int -my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b) +int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b) { - my_ulonglong a_t= TIME_to_ulonglong_datetime(a); - my_ulonglong b_t= TIME_to_ulonglong_datetime(b); + ulonglong a_t= TIME_to_ulonglong_datetime(a); + ulonglong b_t= TIME_to_ulonglong_datetime(b); + if (a_t < b_t) + return -1; if (a_t > b_t) return 1; - else if (a_t < b_t) + + if (a->second_part < b->second_part) return -1; + if (a->second_part > b->second_part) + return 1; return 0; } diff --git a/sql/udf_example.c b/sql/udf_example.c index 9b8f65a4a74..788582e32b6 100644 --- a/sql/udf_example.c +++ b/sql/udf_example.c @@ -139,12 +139,12 @@ typedef long long longlong; #include <mysql.h> #include <ctype.h> +#ifdef HAVE_DLOPEN + #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST) static pthread_mutex_t LOCK_hostname; #endif -#ifdef HAVE_DLOPEN - /* These must be right or mysqld will not find the symbol! */ my_bool metaphon_init(UDF_INIT *initid, UDF_ARGS *args, char *message); diff --git a/sql/unireg.cc b/sql/unireg.cc index 3b1836aeb88..7087ec93804 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -411,10 +411,10 @@ int rea_create_table(THD *thd, const char *path, DBUG_ASSERT(*fn_rext(frm_name)); if (thd->variables.keep_files_on_create) create_info->options|= HA_CREATE_KEEP_FILES; - if (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info)) - goto err_handler; - if (!create_info->frm_only && ha_create_table(thd, path, db, table_name, - create_info,0)) + if (!create_info->frm_only && + (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG, + create_info) || + ha_create_table(thd, path, db, table_name, create_info, 0))) goto err_handler; DBUG_RETURN(0); diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 86dcbf8d732..ed6ff18f980 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -522,8 +522,8 @@ int ha_archive::open(const char *name, int mode, uint open_options) { DBUG_RETURN(0); } - else - DBUG_RETURN(rc); + + DBUG_RETURN(rc); } @@ -993,6 +993,7 @@ int ha_archive::rnd_init(bool scan) /* We rewind the file so that we can read from the beginning if scan */ if (scan) { + scan_rows= stats.records; DBUG_PRINT("info", ("archive will retrieve %llu rows", (unsigned long long) scan_rows)); @@ -1461,7 +1462,6 @@ int ha_archive::info(uint flag) stats.records= share->rows_recorded; pthread_mutex_unlock(&share->mutex); - scan_rows= stats.records; stats.deleted= 0; DBUG_PRINT("ha_archive", ("Stats rows is %d\n", (int)stats.records)); @@ -1472,11 +1472,12 @@ int ha_archive::info(uint flag) VOID(my_stat(share->data_file_name, &file_stat, MYF(MY_WME))); - stats.mean_rec_length= table->s->reclength + buffer.alloced_length(); stats.data_file_length= file_stat.st_size; stats.create_time= (ulong) file_stat.st_ctime; stats.update_time= (ulong) file_stat.st_mtime; - stats.max_data_file_length= share->rows_recorded * stats.mean_rec_length; + stats.mean_rec_length= stats.records ? + stats.data_file_length / stats.records : table->s->reclength; + stats.max_data_file_length= MAX_FILE_SIZE; } stats.delete_length= 0; stats.index_file_length=0; @@ -1574,10 +1575,8 @@ int ha_archive::check(THD* thd, HA_CHECK_OPT* check_opt) share->crashed= FALSE; DBUG_RETURN(HA_ADMIN_CORRUPT); } - else - { - DBUG_RETURN(HA_ADMIN_OK); - } + + DBUG_RETURN(HA_ADMIN_OK); } /* diff --git a/storage/blackhole/ha_blackhole.cc b/storage/blackhole/ha_blackhole.cc index 357496fe095..e3ba111043b 100644 --- a/storage/blackhole/ha_blackhole.cc +++ b/storage/blackhole/ha_blackhole.cc @@ -105,7 +105,7 @@ int ha_blackhole::update_row(const uchar *old_data, uchar *new_data) { DBUG_ENTER("ha_blackhole::update_row"); THD *thd= ha_thd(); - if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query == NULL) + if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query() == NULL) DBUG_RETURN(0); DBUG_RETURN(HA_ERR_WRONG_COMMAND); } @@ -114,7 +114,7 @@ int ha_blackhole::delete_row(const uchar *buf) { DBUG_ENTER("ha_blackhole::delete_row"); THD *thd= ha_thd(); - if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query == NULL) + if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query() == NULL) DBUG_RETURN(0); DBUG_RETURN(HA_ERR_WRONG_COMMAND); } @@ -130,7 +130,7 @@ int ha_blackhole::rnd_next(uchar *buf) { DBUG_ENTER("ha_blackhole::rnd_next"); THD *thd= ha_thd(); - if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query == NULL) + if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query() == NULL) DBUG_RETURN(0); DBUG_RETURN(HA_ERR_END_OF_FILE); } @@ -212,7 +212,7 @@ int ha_blackhole::index_read_map(uchar * buf, const uchar * key, { DBUG_ENTER("ha_blackhole::index_read"); THD *thd= ha_thd(); - if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query == NULL) + if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query() == NULL) DBUG_RETURN(0); DBUG_RETURN(HA_ERR_END_OF_FILE); } @@ -224,7 +224,7 @@ int ha_blackhole::index_read_idx_map(uchar * buf, uint idx, const uchar * key, { DBUG_ENTER("ha_blackhole::index_read_idx"); THD *thd= ha_thd(); - if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query == NULL) + if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query() == NULL) DBUG_RETURN(0); DBUG_RETURN(HA_ERR_END_OF_FILE); } @@ -235,7 +235,7 @@ int ha_blackhole::index_read_last_map(uchar * buf, const uchar * key, { DBUG_ENTER("ha_blackhole::index_read_last"); THD *thd= ha_thd(); - if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query == NULL) + if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query() == NULL) DBUG_RETURN(0); DBUG_RETURN(HA_ERR_END_OF_FILE); } diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc index ad536d40002..3fda2239b34 100644 --- a/storage/csv/ha_tina.cc +++ b/storage/csv/ha_tina.cc @@ -1606,8 +1606,8 @@ int ha_tina::check(THD* thd, HA_CHECK_OPT* check_opt) share->crashed= TRUE; DBUG_RETURN(HA_ADMIN_CORRUPT); } - else - DBUG_RETURN(HA_ADMIN_OK); + + DBUG_RETURN(HA_ADMIN_OK); } diff --git a/storage/federatedx/Makefile.am b/storage/federatedx/Makefile.am index 6dbeff1207a..ad1328247ec 100644 --- a/storage/federatedx/Makefile.am +++ b/storage/federatedx/Makefile.am @@ -22,7 +22,6 @@ pkgplugin_LTLIBRARIES = @plugin_federated_shared_target@ ha_federatedx_la_LDFLAGS = -module -rpath $(pkgplugindir) ha_federatedx_la_CXXFLAGS= $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN ha_federatedx_la_CFLAGS = $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN -ha_federatedx_la_SOURCES = ha_federatedx.cc EXTRA_LIBRARIES = libfederatedx.a diff --git a/storage/federatedx/ha_federatedx.cc b/storage/federatedx/ha_federatedx.cc index 4d4b25da058..308215fe839 100644 --- a/storage/federatedx/ha_federatedx.cc +++ b/storage/federatedx/ha_federatedx.cc @@ -390,8 +390,8 @@ int federatedx_db_init(void *p) DBUG_ENTER("federatedx_db_init"); handlerton *federatedx_hton= (handlerton *)p; federatedx_hton->state= SHOW_OPTION_YES; - /* This is no longer needed for plugin storage engines */ - federatedx_hton->db_type= DB_TYPE_DEFAULT; + /* Needed to work with old .frm files */ + federatedx_hton->db_type= DB_TYPE_FEDERATED_DB; federatedx_hton->savepoint_offset= sizeof(ulong); federatedx_hton->close_connection= ha_federatedx::disconnect; federatedx_hton->savepoint_set= ha_federatedx::savepoint_set; @@ -1785,14 +1785,22 @@ int ha_federatedx::close(void) if (stored_result) retval= free_result(); - /* Disconnect from mysql */ - if ((txn= get_txn(thd, true))) + /* Disconnect from mysql. thd may be null during refresh */ + txn= thd ? get_txn(thd, true) : new federatedx_txn(); + + if (txn) + { txn->release(&io); + + DBUG_ASSERT(io == NULL); - DBUG_ASSERT(io == NULL); + if ((error= free_share(txn, share))) + retval= error; + + if (!thd) + delete txn; - if ((error= free_share(txn, share))) - retval= error; + } DBUG_RETURN(retval); } diff --git a/storage/heap/hp_write.c b/storage/heap/hp_write.c index 29701f8ecbe..4e8fa7e3580 100644 --- a/storage/heap/hp_write.c +++ b/storage/heap/hp_write.c @@ -196,13 +196,10 @@ int hp_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, HP_SHARE *share = info->s; int flag; ulong halfbuff,hashnr,first_index; - uchar *ptr_to_rec,*ptr_to_rec2; - HASH_INFO *empty,*gpos,*gpos2,*pos; + uchar *UNINIT_VAR(ptr_to_rec),*UNINIT_VAR(ptr_to_rec2); + HASH_INFO *empty,*UNINIT_VAR(gpos),*UNINIT_VAR(gpos2),*pos; DBUG_ENTER("hp_write_key"); - LINT_INIT(gpos); LINT_INIT(gpos2); - LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2); - flag=0; if (!(empty= hp_find_free_hash(share,&keyinfo->block,share->records))) DBUG_RETURN(-1); /* No more memory */ diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 8cb196bf983..b8251a99105 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -1268,7 +1268,7 @@ dict_col_name_is_reserved( ulint i; for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) { - if (strcmp(name, reserved_names[i]) == 0) { + if (innobase_strcasecmp(name, reserved_names[i]) == 0) { return(TRUE); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index a73932e15dc..7db078add05 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -41,7 +41,7 @@ have disabled the InnoDB inlining in this file. */ #include <mysql/plugin.h> #ifndef MYSQL_SERVER -/* This is needed because of Bug #3596. Let us hope that pthread_mutex_t +/* This is needed because of Bug #3596. Let us hope that pthread_mutex_t is defined the same in both builds: the MySQL server and the InnoDB plugin. */ extern pthread_mutex_t LOCK_thread_count; #endif /* MYSQL_SERVER */ @@ -54,6 +54,7 @@ static ulong commit_threads = 0; static pthread_mutex_t commit_threads_m; static pthread_cond_t commit_cond; static pthread_mutex_t commit_cond_m; +static pthread_mutex_t analyze_mutex; static bool innodb_inited = 0; /* @@ -155,17 +156,36 @@ static void free_share(INNOBASE_SHARE *share); static int innobase_close_connection(handlerton *hton, THD* thd); static int innobase_commit(handlerton *hton, THD* thd, bool all); static int innobase_rollback(handlerton *hton, THD* thd, bool all); -static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, +static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, void *savepoint); static int innobase_savepoint(handlerton *hton, THD* thd, void *savepoint); -static int innobase_release_savepoint(handlerton *hton, THD* thd, +static int innobase_release_savepoint(handlerton *hton, THD* thd, void *savepoint); static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); +/*********************************************************************** +This function checks each index name for a table against reserved +system default primary index name 'GEN_CLUST_INDEX'. If a name matches, +this function pushes an error message to the client, and returns true. */ +static +bool +innobase_index_name_is_reserved( +/*============================*/ + /* out: true if index name matches a + reserved name */ + const trx_t* trx, /* in: InnoDB transaction handle */ + const TABLE* form, /* in: information on table + columns and indexes */ + const char* norm_name); /* in: table name */ + static const char innobase_hton_name[]= "InnoDB"; +/* "GEN_CLUST_INDEX" is the name reserved for Innodb default +system primary index. */ +static const char innobase_index_reserve_name[]= "GEN_CLUST_INDEX"; + /** @brief Initialize the default value of innodb_commit_concurrency. Once InnoDB is running, the innodb_commit_concurrency must not change @@ -818,7 +838,22 @@ innobase_get_cset_width( *mbminlen = cs->mbminlen; *mbmaxlen = cs->mbmaxlen; } else { - ut_a(cset == 0); + if (current_thd + && (thd_sql_command(current_thd) == SQLCOM_DROP_TABLE)) { + + /* Fix bug#46256: allow tables to be dropped if the + collation is not found, but issue a warning. */ + if ((global_system_variables.log_warnings) + && (cset != 0)){ + + sql_print_warning( + "Unknown collation #%lu.", cset); + } + } else { + + ut_a(cset == 0); + } + *mbminlen = *mbmaxlen = 0; } } @@ -1908,6 +1943,7 @@ innobase_init( pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST); pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST); pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST); + pthread_mutex_init(&analyze_mutex, MY_MUTEX_INIT_FAST); pthread_cond_init(&commit_cond, NULL); innodb_inited= 1; @@ -1947,6 +1983,7 @@ innobase_end(handlerton *hton, ha_panic_function type) pthread_mutex_destroy(&prepare_commit_mutex); pthread_mutex_destroy(&commit_threads_m); pthread_mutex_destroy(&commit_cond_m); + pthread_mutex_destroy(&analyze_mutex); pthread_cond_destroy(&commit_cond); } @@ -2191,6 +2228,8 @@ innobase_rollback( innobase_release_stat_resources(trx); + trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */ + /* If we had reserved the auto-inc lock for some table (if we come here to roll back the latest SQL statement) we release it now before a possibly lengthy rollback */ @@ -2525,12 +2564,28 @@ ha_innobase::innobase_initialize_autoinc() dict_table_autoinc_initialize(innodb_table, auto_inc); - } else { + } else if (error == DB_RECORD_NOT_FOUND) { ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Error: (%lu) Couldn't read " - "the MAX(%s) autoinc value from the " - "index (%s).\n", error, col_name, index->name); - } + fprintf(stderr, " InnoDB: MySQL and InnoDB data " + "dictionaries are out of sync.\n" + "InnoDB: Unable to find the AUTOINC column %s in the " + "InnoDB table %s.\n" + "InnoDB: We set the next AUTOINC column value to the " + "maximum possible value,\n" + "InnoDB: in effect disabling the AUTOINC next value " + "generation.\n" + "InnoDB: You can either set the next AUTOINC value " + "explicitly using ALTER TABLE\n" + "InnoDB: or fix the data dictionary by recreating " + "the table.\n", + col_name, index->table->name); + + auto_inc = 0xFFFFFFFFFFFFFFFFULL; + + dict_table_autoinc_initialize(innodb_table, auto_inc); + + error = DB_SUCCESS; + } /* else other errors are still fatal */ return(ulong(error)); } @@ -2741,7 +2796,6 @@ retry: if (dict_table_autoinc_read(prebuilt->table) == 0) { error = innobase_initialize_autoinc(); - /* Should always succeed! */ ut_a(error == DB_SUCCESS); } @@ -3201,7 +3255,10 @@ ha_innobase::store_key_val_for_row( } else if (mysql_type == MYSQL_TYPE_TINY_BLOB || mysql_type == MYSQL_TYPE_MEDIUM_BLOB || mysql_type == MYSQL_TYPE_BLOB - || mysql_type == MYSQL_TYPE_LONG_BLOB) { + || mysql_type == MYSQL_TYPE_LONG_BLOB + /* MYSQL_TYPE_GEOMETRY data is treated + as BLOB data in innodb. */ + || mysql_type == MYSQL_TYPE_GEOMETRY) { CHARSET_INFO* cs; ulint key_len; @@ -5142,6 +5199,28 @@ create_table_def( } } + /* First check whether the column to be added has a + system reserved name. */ + if (dict_col_name_is_reserved(field->field_name)){ + push_warning_printf( + (THD*) trx->mysql_thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_CREATE_TABLE, + "Error creating table '%s' with " + "column name '%s'. '%s' is a " + "reserved name. Please try to " + "re-create the table with a " + "different column name.", + table->name, (char*) field->field_name, + (char*) field->field_name); + + dict_mem_table_free(table); + trx_commit_for_mysql(trx); + + error = DB_ERROR; + goto error_ret; + } + dict_mem_table_add_col(table, table->heap, (char*) field->field_name, col_type, @@ -5157,6 +5236,7 @@ create_table_def( innodb_check_for_record_too_big_error(flags & DICT_TF_COMPACT, error); +error_ret: error = convert_error_code_to_mysql(error, NULL); DBUG_RETURN(error); @@ -5194,6 +5274,9 @@ create_index( n_fields = key->key_parts; + /* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */ + ut_a(innobase_strcasecmp(key->name, innobase_index_reserve_name) != 0); + ind_type = 0; if (key_num == form->s->primary_key) { @@ -5306,8 +5389,8 @@ create_clustered_index_when_no_primary( /* We pass 0 as the space id, and determine at a lower level the space id where to store the table */ - - index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX", + index = dict_mem_index_create(table_name, + innobase_index_reserve_name, 0, DICT_CLUSTERED, 0); error = row_create_index_for_mysql(index, trx, NULL); @@ -5368,13 +5451,15 @@ ha_innobase::create( 1. <database_name>/<table_name>: for normal table creation 2. full path: for temp table creation, or sym link - When srv_file_per_table is on, check for full path pattern, i.e. + When srv_file_per_table is on and mysqld_embedded is off, + check for full path pattern, i.e. X:\dir\..., X is a driver letter, or \\dir1\dir2\..., UNC path returns error if it is in full path format, but not creating a temp. table. Currently InnoDB does not support symbolic link on Windows. */ if (srv_file_per_table + && !mysqld_embedded && (!create_info->options & HA_LEX_CREATE_TMP_TABLE)) { if ((name[1] == ':') @@ -5439,14 +5524,6 @@ ha_innobase::create( flags |= DICT_TF_COMPACT; } - error = create_table_def(trx, form, norm_name, - create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, - flags); - - if (error) { - goto cleanup; - } - /* Look for a primary key */ primary_key_no= (form->s->primary_key != MAX_KEY ? @@ -5458,6 +5535,22 @@ ha_innobase::create( DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0); + /* Check for name conflicts (with reserved name) for + any user indices to be created. */ + if (innobase_index_name_is_reserved(trx, form, norm_name)) { + error = -1; + goto cleanup; + } + + error = create_table_def(trx, form, norm_name, + create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, + flags); + + if (error) { + goto cleanup; + } + + /* Create the keys */ if (form->s->keys == 0 || primary_key_no == -1) { @@ -5522,18 +5615,22 @@ ha_innobase::create( setup at this stage and so we use thd. */ /* We need to copy the AUTOINC value from the old table if - this is an ALTER TABLE. */ + this is an ALTER TABLE or CREATE INDEX because CREATE INDEX + does a table copy too. */ if (((create_info->used_fields & HA_CREATE_USED_AUTO) - || thd_sql_command(thd) == SQLCOM_ALTER_TABLE) - && create_info->auto_increment_value != 0) { - - /* Query was ALTER TABLE...AUTO_INCREMENT = x; or - CREATE TABLE ...AUTO_INCREMENT = x; Find out a table - definition from the dictionary and get the current value - of the auto increment field. Set a new value to the - auto increment field if the value is greater than the - maximum value in the column. */ + || thd_sql_command(thd) == SQLCOM_ALTER_TABLE + || thd_sql_command(thd) == SQLCOM_CREATE_INDEX) + && create_info->auto_increment_value > 0) { + + /* Query was one of : + CREATE TABLE ...AUTO_INCREMENT = x; or + ALTER TABLE...AUTO_INCREMENT = x; or + CREATE INDEX x on t(...); + Find out a table definition from the dictionary and get + the current value of the auto increment field. Set a new + value to the auto increment field if the value is greater + than the maximum value in the column. */ auto_inc_value = create_info->auto_increment_value; @@ -6355,9 +6452,15 @@ ha_innobase::analyze( THD* thd, /* in: connection thread handle */ HA_CHECK_OPT* check_opt) /* in: currently ignored */ { + /* Serialize ANALYZE TABLE inside InnoDB, see + Bug#38996 Race condition in ANALYZE TABLE */ + pthread_mutex_lock(&analyze_mutex); + /* Simply call ::info() with all the flags */ info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE); + pthread_mutex_unlock(&analyze_mutex); + return(0); } @@ -6954,8 +7057,9 @@ ha_innobase::external_lock( { ulong const binlog_format= thd_binlog_format(thd); ulong const tx_isolation = thd_tx_isolation(current_thd); - if (tx_isolation <= ISO_READ_COMMITTED && - binlog_format == BINLOG_FORMAT_STMT) + if (tx_isolation <= ISO_READ_COMMITTED + && binlog_format == BINLOG_FORMAT_STMT + && thd_binlog_filter_ok(thd)) { char buf[256]; my_snprintf(buf, sizeof(buf), @@ -7792,6 +7896,7 @@ ha_innobase::get_auto_increment( AUTOINC counter after attempting to insert the row. */ if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) { ulonglong need; + ulonglong current; ulonglong next_value; ulonglong col_max_value; @@ -7800,11 +7905,12 @@ ha_innobase::get_auto_increment( col_max_value = innobase_get_int_col_max_value( table->next_number_field); + current = *first_value > col_max_value ? autoinc : *first_value; need = *nb_reserved_values * increment; /* Compute the last value in the interval */ next_value = innobase_next_autoinc( - *first_value, need, offset, col_max_value); + current, need, offset, col_max_value); prebuilt->autoinc_last_value = next_value; @@ -8404,6 +8510,46 @@ static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff) return 0; } +/*********************************************************************** +This function checks each index name for a table against reserved +system default primary index name 'GEN_CLUST_INDEX'. If a name matches, +this function pushes an error message to the client, and returns true. */ +static +bool +innobase_index_name_is_reserved( +/*============================*/ + /* out: true if an index name + matches the reserved name */ + const trx_t* trx, /* in: InnoDB transaction handle */ + const TABLE* form, /* in: information on table + columns and indexes */ + const char* norm_name) /* in: table name */ +{ + KEY* key; + uint key_num; /* index number */ + + for (key_num = 0; key_num < form->s->keys; key_num++) { + key = form->key_info + key_num; + + if (innobase_strcasecmp(key->name, + innobase_index_reserve_name) == 0) { + /* Push warning to mysql */ + push_warning_printf((THD*) trx->mysql_thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_CREATE_TABLE, + "Cannot Create Index with name " + "'%s'. The name is reserved " + "for the system default primary " + "index.", + innobase_index_reserve_name); + + return(true); + } + } + + return(false); +} + static SHOW_VAR innodb_status_variables_export[]= { {"Innodb", (char*) &show_innodb_vars, SHOW_FUNC}, {NullS, NullS, SHOW_LONG} diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 8ca72ee1a60..9ddb516c3dc 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -252,4 +252,11 @@ int thd_binlog_format(const MYSQL_THD thd); @param all TRUE <=> rollback main transaction. */ void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); + +/** + Check if binary logging is filtered for thread's current db. + @param thd Thread handle + @retval 1 the query is not filtered, 0 otherwise. +*/ +bool thd_binlog_filter_ok(const MYSQL_THD thd); } diff --git a/storage/innobase/os/os0proc.c b/storage/innobase/os/os0proc.c index a99fe8b6a0e..f00475fc528 100644 --- a/storage/innobase/os/os0proc.c +++ b/storage/innobase/os/os0proc.c @@ -591,6 +591,7 @@ os_mem_alloc_large( fprintf(stderr, "InnoDB: HugeTLB: Warning: Failed to" " attach shared memory segment, errno %d\n", errno); + ptr = NULL; } /* Remove the shared memory segment so that it will be diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 6ec466cf995..4fcb1fbf9f2 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -1788,7 +1788,6 @@ row_create_table_for_mysql( const char* table_name; ulint table_name_len; ulint err; - ulint i; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); #ifdef UNIV_SYNC_DEBUG @@ -1827,18 +1826,6 @@ row_create_table_for_mysql( return(DB_ERROR); } - /* Check that no reserved column names are used. */ - for (i = 0; i < dict_table_get_n_user_cols(table); i++) { - if (dict_col_name_is_reserved( - dict_table_get_col_name(table, i))) { - - dict_mem_table_free(table); - trx_commit_for_mysql(trx); - - return(DB_ERROR); - } - } - trx_start_if_not_started(trx); /* The table name is prefixed with the database name and a '/'. @@ -2102,7 +2089,7 @@ Scans a table create SQL string and adds to the data dictionary the foreign key constraints declared in the string. This function should be called after the indexes for a table have been created. Each foreign key constraint must be accompanied with indexes in -bot participating tables. The indexes are allowed to contain more +both participating tables. The indexes are allowed to contain more fields than mentioned in the constraint. Check also that foreign key constraints which reference this table are ok. */ diff --git a/storage/innodb_plugin/CMakeLists.txt b/storage/innodb_plugin/CMakeLists.txt index a4de7fd1a2a..36e157ae736 100644 --- a/storage/innodb_plugin/CMakeLists.txt +++ b/storage/innodb_plugin/CMakeLists.txt @@ -18,14 +18,20 @@ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") + +# Starting at 5.1.38, MySQL CMake files are simplified. But the plugin +# CMakeLists.txt still needs to work with previous versions of MySQL. +IF (MYSQL_VERSION_ID GREATER "50137") + INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake") +ENDIF (MYSQL_VERSION_ID GREATER "50137") + IF (CMAKE_SIZEOF_VOID_P MATCHES 8) SET(WIN64 TRUE) ENDIF (CMAKE_SIZEOF_VOID_P MATCHES 8) # Include directories under innodb_plugin INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innodb_plugin/include - ${CMAKE_SOURCE_DIR}/storage/innodfb_plugin/handler) + ${CMAKE_SOURCE_DIR}/storage/innodb_plugin/handler) # Include directories under mysql INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include @@ -36,10 +42,10 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include # Removing compiler optimizations for innodb/mem/* files on 64-bit Windows # due to 64-bit compiler error, See MySQL Bug #19424, #36366, #34297 -IF(MSVC AND $(WIN64)) +IF (MSVC AND $(WIN64)) SET_SOURCE_FILES_PROPERTIES(mem/mem0mem.c mem/mem0pool.c PROPERTIES COMPILE_FLAGS -Od) -ENDIF(MSVC AND $(WIN64)) +ENDIF (MSVC AND $(WIN64)) SET(INNODB_PLUGIN_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c buf/buf0buddy.c buf/buf0buf.c buf/buf0flu.c buf/buf0lru.c buf/buf0rea.c @@ -74,7 +80,7 @@ SET(INNODB_PLUGIN_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea usr/usr0sess.c ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c ut/ut0list.c ut/ut0wqueue.c) -ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DINNODB_RW_LOCKS_USE_ATOMICS -DIB_HAVE_PAUSE_INSTRUCTION) +ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DIB_HAVE_PAUSE_INSTRUCTION) #Disable storage engine, as we are using XtraDB #MYSQL_STORAGE_ENGINE(INNODB_PLUGIN) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 2b04c06f0e8..70225ffd9d9 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,229 @@ +2009-10-29 The InnoDB Team + + * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result, + mysql-test/innodb-autoinc.test: + Fix Bug#47125 auto_increment start value is ignored if an index is + created and engine=innodb + +2009-10-29 The InnoDB Team + + * handler/ha_innodb.cc, mysql-test/innodb_bug47777.result, + mysql-test/innodb_bug47777.test: + Fix Bug#47777 innodb dies with spatial pk: Failing assertion: buf <= + original_buf + buf_len + +2009-10-29 The InnoDB Team + + * handler/ha_innodb.cc: + Fix Bug#38996 Race condition in ANALYZE TABLE + +2009-10-29 The InnoDB Team + + * handler/ha_innodb.cc: + Fix bug#42383: Can't create table 'test.bug39438' + +2009-10-29 The InnoDB Team + + * os/os0proc.c: + Fix Bug#48237 Error handling in os_mem_alloc_large appears to + be incorrect + +2009-10-29 The InnoDB Team + + * buf/buf0buf.c, buf/buf0lru.c, include/buf0buf.h, include/buf0buf.ic: + Fix corruption of the buf_pool->LRU_old list and improve debug + assertions. + +2009-10-28 The InnoDB Team + + * srv/srv0start.c: + Fix Bug#41490 After enlargement of InnoDB page size, the error message + become inaccurate + +2009-10-26 The InnoDB Team + + * row/row0ins.c: + When allocating a data tuple, zero out the system fields in order + to avoid Valgrind warnings about uninitialized fields in + dtuple_validate(). + +2009-10-22 The InnoDB Team + + * handler/ha_innodb.cc, mysql-test/innodb-zip.result, + mysql-test/innodb-zip.test, mysql-test/innodb_bug44369.result, + mysql-test/innodb_bug44369.test: + Fix Bug#47233 Innodb calls push_warning(MYSQL_ERROR::WARN_LEVEL_ERROR) + +2009-10-19 The InnoDB Team + + * mysql-test/innodb_information_schema.test: + Fix Bug#47808 innodb_information_schema.test fails when run under + valgrind + +2009-10-15 The InnoDB Team + + * include/page0page.ic: + Fix Bug#47058 Failure to compile innodb_plugin on solaris 10u7 + spro + cc/CC 5.10 + +2009-10-05 The InnoDB Team + + * buf/buf0buf.c: + Do not invalidate buffer pool while an LRU batch is active. Added code + to buf_pool_invalidate() to wait for the running batches to finish. + +2009-10-01 The InnoDB Team + + * handler/ha_innodb.cc: + Fix Bug#47763 typo in error message: Failed to open table %s after %lu + attemtps. + +2009-10-01 The InnoDB Team + + * fsp/fsp0fsp.c, row/row0merge.c: + Clean up after a crash during DROP INDEX. When InnoDB crashes + while dropping an index, ensure that the index will be completely + dropped during crash recovery. The MySQL .frm file may still + contain the dropped index, but there is little that we can do + about it. + +2009-09-28 The InnoDB Team + + * handler/ha_innodb.cc: + When a secondary index exists in the MySQL .frm file but not in + the InnoDB data dictionary, return an error instead of letting an + assertion fail in index_read. + +2009-09-28 The InnoDB Team + + * btr/btr0btr.c, buf/buf0buf.c, include/page0page.h, + include/page0zip.h, page/page0cur.c, page/page0page.c, + page/page0zip.c: + Do not write to PAGE_INDEX_ID when restoring an uncompressed page + after a compression failure. The field should only be written + when creating a B-tree page. This fix addresses a race condition + in a debug assertion. + +2009-09-28 The InnoDB Team + + * fil/fil0fil.c: + Try to prevent the reuse of tablespace identifiers after InnoDB + has crashed during table creation. Also, refuse to start if files + with duplicate tablespace identifiers are encountered. + +2009-09-25 The InnoDB Team + + * include/os0file.h, os/os0file.c: + Fix Bug#47055 unconditional exit(1) on ERROR_WORKING_SET_QUOTA + 1453 (0x5AD) for InnoDB backend + +2009-09-19 The InnoDB Team + + * handler/ha_innodb.cc, mysql-test/innodb-consistent-master.opt, + mysql-test/innodb-consistent.result, + mysql-test/innodb-consistent.test: + Fix Bug#37232 Innodb might get too many read locks for DML with + repeatable-read + +2009-09-19 The InnoDB Team + + * fsp/fsp0fsp.c: + Fix Bug#31183 Tablespace full problems not reported in error log, + error message unclear + +2009-09-17 The InnoDB Team + + * mysql-test/innodb-zip.result, mysql-test/innodb-zip.test: + Make the test pass with zlib 1.2.3.3. Apparently, the definition + of compressBound() has changed between zlib versions, and the + maximum record size of a table with 1K compressed page size has + been reduced by one byte. This is an arbitrary test. In practical + applications, for good write performance, the compressed page size + should be chosen to be bigger than the absolute minimum. + +2009-09-16 The InnoDB Team + + * handler/ha_innodb.cc: + Fix Bug#46256 drop table with unknown collation crashes innodb + +2009-09-16 The InnoDB Team + + * dict/dict0dict.c, handler/ha_innodb.cc, + mysql-test/innodb_bug44369.result, mysql-test/innodb_bug44369.test, + row/row0mysql.c: + Fix Bug#44369 InnoDB: Does not uniformly disallow disallowed column + names + +2009-09-16 The InnoDB Team + + * handler/ha_innodb.cc, include/db0err.h, + mysql-test/innodb_bug46000.result, mysql-test/innodb_bug46000.test: + Fix Bug#46000 using index called GEN_CLUST_INDEX crashes server + +2009-09-02 The InnoDB Team + + * include/lock0lock.h, include/row0mysql.h, lock/lock0lock.c, + row/row0mysql.c: + Fix a regression introduced by the fix for MySQL bug#26316. We check + whether a transaction holds any AUTOINC locks before we acquire + the kernel mutex and release those locks. + +2009-08-27 The InnoDB Team + + * dict/dict0dict.c, include/dict0dict.h, + mysql-test/innodb_bug44571.result, mysql-test/innodb_bug44571.test: + Fix Bug#44571 InnoDB Plugin crashes on ADD INDEX + +2009-08-27 The InnoDB Team + + * row/row0merge.c: + Fix a bug in the merge sort that can corrupt indexes in fast index + creation. Add some consistency checks. Check that the number of + records remains constant in every merge sort pass. + +2009-08-27 The InnoDB Team + + * buf/buf0buf.c, buf/buf0lru.c, buf/buf0rea.c, handler/ha_innodb.cc, + include/buf0buf.h, include/buf0buf.ic, include/buf0lru.h, + include/ut0ut.h, ut/ut0ut.c: + Make it possible to tune the buffer pool LRU eviction policy to be + more resistant against index scans. Introduce the settable global + variables innodb_old_blocks_pct and innodb_old_blocks_time for + controlling the buffer pool eviction policy. The parameter + innodb_old_blocks_pct (5..95) controls the desired amount of "old" + blocks in the LRU list. The default is 37, corresponding to the + old fixed ratio of 3/8. Each time a block is accessed, it will be + moved to the "new" blocks if its first access was at least + innodb_old_blocks_time milliseconds ago (default 0, meaning every + block). The idea is that in index scans, blocks will be accessed + a few times within innodb_old_blocks_time, and they will remain in + the "old" section of the LRU list. Thus, when innodb_old_blocks_time + is nonzero, blocks retrieved for one-time index scans will be more + likely candidates for eviction than blocks that are accessed in + random patterns. + +2009-08-26 The InnoDB Team + + * handler/ha_innodb.cc, os/os0file.c: + Fix Bug#42885 buf_read_ahead_random, buf_read_ahead_linear counters, + thread wakeups + +2009-08-20 The InnoDB Team + + * lock/lock0lock.c: + Fix Bug#46650 Innodb assertion autoinc_lock == lock in + lock_table_remove_low on INSERT SELECT + +2009-08-13 The InnoDB Team + + * handler/handler0alter.cc: + Fix Bug#46657 InnoDB plugin: invalid read in index_merge_innodb test + (Valgrind) + +2009-08-11 The InnoDB Team + + InnoDB Plugin 1.0.4 released + 2009-07-20 The InnoDB Team * buf/buf0rea.c, handler/ha_innodb.cc, include/srv0srv.h, diff --git a/storage/innodb_plugin/Makefile.am b/storage/innodb_plugin/Makefile.am index 50a3c1e6cab..5c71fe18d14 100644 --- a/storage/innodb_plugin/Makefile.am +++ b/storage/innodb_plugin/Makefile.am @@ -31,7 +31,6 @@ DEFS= @DEFS@ noinst_HEADERS= \ handler/ha_innodb.h \ - handler/handler0vars.h \ handler/i_s.h \ include/btr0btr.h \ include/btr0btr.ic \ diff --git a/storage/innodb_plugin/README b/storage/innodb_plugin/README deleted file mode 100644 index 56aa8058224..00000000000 --- a/storage/innodb_plugin/README +++ /dev/null @@ -1,29 +0,0 @@ -This is the source of the InnoDB Plugin 1.0.4 for MySQL 5.1 -=========================================================== - -Instructions for compiling the plugin: --------------------------------------- - -1. Get the latest MySQL 5.1 sources from - http://dev.mysql.com/downloads/mysql/5.1.html#source - -2. Replace the contents of the mysql-5.1.N/storage/innobase/ directory - with the contents of this directory. - -3. Optional (only necessary if you are going to run tests from the - mysql-test suite): cd into the innobase directory and run ./setup.sh - -4. Compile MySQL as usual. - -5. Enjoy! - -See the online documentation for more detailed instructions: -http://www.innodb.com/doc/innodb_plugin-1.0/innodb-plugin-installation.html - -For more information about InnoDB visit -http://www.innodb.com - -Please report any problems or issues with the plugin in the InnoDB Forums -http://forums.innodb.com/ or in the MySQL Bugs database http://bugs.mysql.com - -Thank you for using the InnoDB plugin! diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c index 6ba9b36207b..94b34ecece1 100644 --- a/storage/innodb_plugin/btr/btr0btr.c +++ b/storage/innodb_plugin/btr/btr0btr.c @@ -797,7 +797,7 @@ btr_create( buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); } - /* Create a new index page on the the allocated segment page */ + /* Create a new index page on the allocated segment page */ page_zip = buf_block_get_page_zip(block); if (UNIV_LIKELY_NULL(page_zip)) { @@ -1011,7 +1011,26 @@ btr_page_reorganize_low( (!page_zip_compress(page_zip, page, index, NULL))) { /* Restore the old page and exit. */ - buf_frame_copy(page, temp_page); + +#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG + /* Check that the bytes that we skip are identical. */ + ut_a(!memcmp(page, temp_page, PAGE_HEADER)); + ut_a(!memcmp(PAGE_HEADER + PAGE_N_RECS + page, + PAGE_HEADER + PAGE_N_RECS + temp_page, + PAGE_DATA - (PAGE_HEADER + PAGE_N_RECS))); + ut_a(!memcmp(UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + page, + UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + temp_page, + FIL_PAGE_DATA_END)); +#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ + + memcpy(PAGE_HEADER + page, PAGE_HEADER + temp_page, + PAGE_N_RECS - PAGE_N_DIR_SLOTS); + memcpy(PAGE_DATA + page, PAGE_DATA + temp_page, + UNIV_PAGE_SIZE - PAGE_DATA - FIL_PAGE_DATA_END); + +#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG + ut_a(!memcmp(page, temp_page, UNIV_PAGE_SIZE)); +#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ goto func_exit; } @@ -1902,7 +1921,7 @@ func_start: n_uniq, &heap); /* If the new record is less than the existing record - the the split in the middle will copy the existing + the split in the middle will copy the existing record to the new node. */ if (cmp_dtuple_rec(tuple, first_rec, offsets) < 0) { split_rec = page_get_middle_rec(page); diff --git a/storage/innodb_plugin/btr/btr0sea.c b/storage/innodb_plugin/btr/btr0sea.c index faa1c13897e..0a80c61a58d 100644 --- a/storage/innodb_plugin/btr/btr0sea.c +++ b/storage/innodb_plugin/btr/btr0sea.c @@ -957,7 +957,7 @@ btr_search_guess_on_hash( /* Increment the page get statistics though we did not really fix the page: for user info only */ - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; return(TRUE); diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index 0008fcb1271..ff31457d200 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -837,16 +837,35 @@ buf_chunk_not_freed( block = chunk->blocks; for (i = chunk->size; i--; block++) { - mutex_enter(&block->mutex); - - if (buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE - && !buf_flush_ready_for_replace(&block->page)) { + ibool ready; + switch (buf_block_get_state(block)) { + case BUF_BLOCK_ZIP_FREE: + case BUF_BLOCK_ZIP_PAGE: + case BUF_BLOCK_ZIP_DIRTY: + /* The uncompressed buffer pool should never + contain compressed block descriptors. */ + ut_error; + break; + case BUF_BLOCK_NOT_USED: + case BUF_BLOCK_READY_FOR_USE: + case BUF_BLOCK_MEMORY: + case BUF_BLOCK_REMOVE_HASH: + /* Skip blocks that are not being used for + file pages. */ + break; + case BUF_BLOCK_FILE_PAGE: + mutex_enter(&block->mutex); + ready = buf_flush_ready_for_replace(&block->page); mutex_exit(&block->mutex); - return(block); - } - mutex_exit(&block->mutex); + if (!ready) { + + return(block); + } + + break; + } } return(NULL); @@ -966,8 +985,6 @@ buf_pool_init(void) buf_pool->no_flush[i] = os_event_create(NULL); } - buf_pool->ulint_clock = 1; - /* 3. Initialize LRU fields --------------------------- */ /* All fields are initialized by mem_zalloc(). */ @@ -1146,10 +1163,15 @@ buf_relocate( #ifdef UNIV_LRU_DEBUG /* buf_pool->LRU_old must be the first item in the LRU list whose "old" flag is set. */ + ut_a(buf_pool->LRU_old->old); ut_a(!UT_LIST_GET_PREV(LRU, buf_pool->LRU_old) || !UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)->old); ut_a(!UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old) || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old); + } else { + /* Check that the "old" flag is consistent in + the block and its neighbours. */ + buf_page_set_old(dpage, buf_page_is_old(dpage)); #endif /* UNIV_LRU_DEBUG */ } @@ -1471,33 +1493,8 @@ buf_pool_resize(void) } /********************************************************************//** -Moves the block to the start of the LRU list if there is a danger -that the block would drift out of the buffer pool. */ -UNIV_INLINE -void -buf_block_make_young( -/*=================*/ - buf_page_t* bpage) /*!< in: block to make younger */ -{ - ut_ad(!buf_pool_mutex_own()); - - /* Note that we read freed_page_clock's without holding any mutex: - this is allowed since the result is used only in heuristics */ - - if (buf_page_peek_if_too_old(bpage)) { - - buf_pool_mutex_enter(); - /* There has been freeing activity in the LRU list: - best to move to the head of the LRU list */ - - buf_LRU_make_block_young(bpage); - buf_pool_mutex_exit(); - } -} - -/********************************************************************//** Moves a page to the start of the buffer pool LRU list. This high-level -function can be used to prevent an important page from from slipping out of +function can be used to prevent an important page from slipping out of the buffer pool. */ UNIV_INTERN void @@ -1515,6 +1512,36 @@ buf_page_make_young( } /********************************************************************//** +Sets the time of the first access of a page and moves a page to the +start of the buffer pool LRU list if it is too old. This high-level +function can be used to prevent an important page from slipping +out of the buffer pool. */ +static +void +buf_page_set_accessed_make_young( +/*=============================*/ + buf_page_t* bpage, /*!< in/out: buffer block of a + file page */ + unsigned access_time) /*!< in: bpage->access_time + read under mutex protection, + or 0 if unknown */ +{ + ut_ad(!buf_pool_mutex_own()); + ut_a(buf_page_in_file(bpage)); + + if (buf_page_peek_if_too_old(bpage)) { + buf_pool_mutex_enter(); + buf_LRU_make_block_young(bpage); + buf_pool_mutex_exit(); + } else if (!access_time) { + ulint time_ms = ut_time_ms(); + buf_pool_mutex_enter(); + buf_page_set_accessed(bpage, time_ms); + buf_pool_mutex_exit(); + } +} + +/********************************************************************//** Resets the check_index_page_at_flush field of a page if found in the buffer pool. */ UNIV_INTERN @@ -1645,11 +1672,12 @@ buf_page_get_zip( buf_page_t* bpage; mutex_t* block_mutex; ibool must_read; + unsigned access_time; #ifndef UNIV_LOG_DEBUG ut_ad(!ibuf_inside()); #endif - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; for (;;) { buf_pool_mutex_enter(); @@ -1712,14 +1740,13 @@ err_exit: got_block: must_read = buf_page_get_io_fix(bpage) == BUF_IO_READ; + access_time = buf_page_is_accessed(bpage); buf_pool_mutex_exit(); - buf_page_set_accessed(bpage, TRUE); - mutex_exit(block_mutex); - buf_block_make_young(bpage); + buf_page_set_accessed_make_young(bpage, access_time); #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(!bpage->file_page_was_freed); @@ -1812,7 +1839,7 @@ buf_zip_decompress( switch (fil_page_get_type(frame)) { case FIL_PAGE_INDEX: if (page_zip_decompress(&block->page.zip, - block->frame)) { + block->frame, TRUE)) { return(TRUE); } @@ -2000,7 +2027,7 @@ buf_page_get_gen( mtr_t* mtr) /*!< in: mini-transaction */ { buf_block_t* block; - ibool accessed; + unsigned access_time; ulint fix_type; ibool must_read; @@ -2016,7 +2043,7 @@ buf_page_get_gen( #ifndef UNIV_LOG_DEBUG ut_ad(!ibuf_inside() || ibuf_page(space, zip_size, offset, NULL)); #endif - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; loop: block = guess; buf_pool_mutex_enter(); @@ -2243,17 +2270,16 @@ wait_until_unfixed: UNIV_MEM_ASSERT_RW(&block->page, sizeof block->page); buf_block_buf_fix_inc(block, file, line); - buf_pool_mutex_exit(); - /* Check if this is the first access to the page */ + mutex_exit(&block->mutex); - accessed = buf_page_is_accessed(&block->page); + /* Check if this is the first access to the page */ - buf_page_set_accessed(&block->page, TRUE); + access_time = buf_page_is_accessed(&block->page); - mutex_exit(&block->mutex); + buf_pool_mutex_exit(); - buf_block_make_young(&block->page); + buf_page_set_accessed_make_young(&block->page, access_time); #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(!block->page.file_page_was_freed); @@ -2306,7 +2332,7 @@ wait_until_unfixed: mtr_memo_push(mtr, block, fix_type); - if (!accessed) { + if (!access_time) { /* In the case of a first access, try to apply linear read-ahead */ @@ -2336,7 +2362,7 @@ buf_page_optimistic_get_func( ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mini-transaction */ { - ibool accessed; + unsigned access_time; ibool success; ulint fix_type; @@ -2353,14 +2379,16 @@ buf_page_optimistic_get_func( } buf_block_buf_fix_inc(block, file, line); - accessed = buf_page_is_accessed(&block->page); - buf_page_set_accessed(&block->page, TRUE); mutex_exit(&block->mutex); - buf_block_make_young(&block->page); + /* Check if this is the first access to the page. + We do a dirty read on purpose, to avoid mutex contention. + This field is only used for heuristic purposes; it does not + affect correctness. */ - /* Check if this is the first access to the page */ + access_time = buf_page_is_accessed(&block->page); + buf_page_set_accessed_make_young(&block->page, access_time); ut_ad(!ibuf_inside() || ibuf_page(buf_block_get_space(block), @@ -2412,7 +2440,7 @@ buf_page_optimistic_get_func( #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(block->page.file_page_was_freed == FALSE); #endif - if (UNIV_UNLIKELY(!accessed)) { + if (UNIV_UNLIKELY(!access_time)) { /* In the case of a first access, try to apply linear read-ahead */ @@ -2425,7 +2453,7 @@ buf_page_optimistic_get_func( ut_a(ibuf_count_get(buf_block_get_space(block), buf_block_get_page_no(block)) == 0); #endif - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; return(TRUE); } @@ -2473,8 +2501,20 @@ buf_page_get_known_nowait( mutex_exit(&block->mutex); - if (mode == BUF_MAKE_YOUNG) { - buf_block_make_young(&block->page); + if (mode == BUF_MAKE_YOUNG && buf_page_peek_if_too_old(&block->page)) { + buf_pool_mutex_enter(); + buf_LRU_make_block_young(&block->page); + buf_pool_mutex_exit(); + } else if (!buf_page_is_accessed(&block->page)) { + /* Above, we do a dirty read on purpose, to avoid + mutex contention. The field buf_page_t::access_time + is only used for heuristic purposes. Writes to the + field must be protected by mutex, however. */ + ulint time_ms = ut_time_ms(); + + buf_pool_mutex_enter(); + buf_page_set_accessed(&block->page, time_ms); + buf_pool_mutex_exit(); } ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD)); @@ -2513,7 +2553,7 @@ buf_page_get_known_nowait( || (ibuf_count_get(buf_block_get_space(block), buf_block_get_page_no(block)) == 0)); #endif - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; return(TRUE); } @@ -2589,7 +2629,7 @@ buf_page_try_get_func( #endif /* UNIV_DEBUG_FILE_ACCESSES */ buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK); - buf_pool->n_page_gets++; + buf_pool->stat.n_page_gets++; #ifdef UNIV_IBUF_COUNT_DEBUG ut_a(ibuf_count_get(buf_block_get_space(block), @@ -2608,10 +2648,10 @@ buf_page_init_low( buf_page_t* bpage) /*!< in: block to init */ { bpage->flush_type = BUF_FLUSH_LRU; - bpage->accessed = FALSE; bpage->io_fix = BUF_IO_NONE; bpage->buf_fix_count = 0; bpage->freed_page_clock = 0; + bpage->access_time = 0; bpage->newest_modification = 0; bpage->oldest_modification = 0; HASH_INVALIDATE(bpage, hash); @@ -2907,6 +2947,7 @@ buf_page_create( buf_frame_t* frame; buf_block_t* block; buf_block_t* free_block = NULL; + ulint time_ms = ut_time_ms(); ut_ad(mtr); ut_ad(space || !zip_size); @@ -2953,7 +2994,7 @@ buf_page_create( buf_LRU_add_block(&block->page, FALSE); buf_block_buf_fix_inc(block, __FILE__, __LINE__); - buf_pool->n_pages_created++; + buf_pool->stat.n_pages_created++; if (zip_size) { void* data; @@ -2990,12 +3031,12 @@ buf_page_create( rw_lock_x_unlock(&block->lock); } + buf_page_set_accessed(&block->page, time_ms); + buf_pool_mutex_exit(); mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX); - buf_page_set_accessed(&block->page, TRUE); - mutex_exit(&block->mutex); /* Delete possible entries for the page from the insert buffer: @@ -3201,7 +3242,7 @@ corrupt: ut_ad(buf_pool->n_pend_reads > 0); buf_pool->n_pend_reads--; - buf_pool->n_pages_read++; + buf_pool->stat.n_pages_read++; if (uncompressed) { rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock, @@ -3221,7 +3262,7 @@ corrupt: BUF_IO_WRITE); } - buf_pool->n_pages_written++; + buf_pool->stat.n_pages_written++; break; @@ -3251,7 +3292,32 @@ void buf_pool_invalidate(void) /*=====================*/ { - ibool freed; + ibool freed; + enum buf_flush i; + + buf_pool_mutex_enter(); + + for (i = BUF_FLUSH_LRU; i < BUF_FLUSH_N_TYPES; i++) { + + /* As this function is called during startup and + during redo application phase during recovery, InnoDB + is single threaded (apart from IO helper threads) at + this stage. No new write batch can be in intialization + stage at this point. */ + ut_ad(buf_pool->init_flush[i] == FALSE); + + /* However, it is possible that a write batch that has + been posted earlier is still not complete. For buffer + pool invalidation to proceed we must ensure there is NO + write activity happening. */ + if (buf_pool->n_flush[i] > 0) { + buf_pool_mutex_exit(); + buf_flush_wait_batch_end(i); + buf_pool_mutex_enter(); + } + } + + buf_pool_mutex_exit(); ut_ad(buf_all_freed()); @@ -3266,6 +3332,14 @@ buf_pool_invalidate(void) ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0); ut_ad(UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0); + buf_pool->freed_page_clock = 0; + buf_pool->LRU_old = NULL; + buf_pool->LRU_old_len = 0; + buf_pool->LRU_flush_ended = 0; + + memset(&buf_pool->stat, 0x00, sizeof(buf_pool->stat)); + buf_refresh_io_stats(); + buf_pool_mutex_exit(); } @@ -3528,6 +3602,7 @@ buf_print(void) "n pending decompressions %lu\n" "n pending reads %lu\n" "n pending flush LRU %lu list %lu single page %lu\n" + "pages made young %lu, not young %lu\n" "pages read %lu, created %lu, written %lu\n", (ulong) size, (ulong) UT_LIST_GET_LEN(buf_pool->LRU), @@ -3538,8 +3613,11 @@ buf_print(void) (ulong) buf_pool->n_flush[BUF_FLUSH_LRU], (ulong) buf_pool->n_flush[BUF_FLUSH_LIST], (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE], - (ulong) buf_pool->n_pages_read, buf_pool->n_pages_created, - (ulong) buf_pool->n_pages_written); + (ulong) buf_pool->stat.n_pages_made_young, + (ulong) buf_pool->stat.n_pages_not_made_young, + (ulong) buf_pool->stat.n_pages_read, + (ulong) buf_pool->stat.n_pages_created, + (ulong) buf_pool->stat.n_pages_written); /* Count the number of blocks belonging to each index in the buffer */ @@ -3744,10 +3822,9 @@ buf_print_io( { time_t current_time; double time_elapsed; - ulint size; + ulint n_gets_diff; ut_ad(buf_pool); - size = buf_pool->curr_size; buf_pool_mutex_enter(); @@ -3755,12 +3832,14 @@ buf_print_io( "Buffer pool size %lu\n" "Free buffers %lu\n" "Database pages %lu\n" + "Old database pages %lu\n" "Modified db pages %lu\n" "Pending reads %lu\n" "Pending writes: LRU %lu, flush list %lu, single page %lu\n", - (ulong) size, + (ulong) buf_pool->curr_size, (ulong) UT_LIST_GET_LEN(buf_pool->free), (ulong) UT_LIST_GET_LEN(buf_pool->LRU), + (ulong) buf_pool->LRU_old_len, (ulong) UT_LIST_GET_LEN(buf_pool->flush_list), (ulong) buf_pool->n_pend_reads, (ulong) buf_pool->n_flush[BUF_FLUSH_LRU] @@ -3772,37 +3851,66 @@ buf_print_io( current_time = time(NULL); time_elapsed = 0.001 + difftime(current_time, buf_pool->last_printout_time); - buf_pool->last_printout_time = current_time; fprintf(file, + "Pages made young %lu, not young %lu\n" + "%.2f youngs/s, %.2f non-youngs/s\n" "Pages read %lu, created %lu, written %lu\n" "%.2f reads/s, %.2f creates/s, %.2f writes/s\n", - (ulong) buf_pool->n_pages_read, - (ulong) buf_pool->n_pages_created, - (ulong) buf_pool->n_pages_written, - (buf_pool->n_pages_read - buf_pool->n_pages_read_old) + (ulong) buf_pool->stat.n_pages_made_young, + (ulong) buf_pool->stat.n_pages_not_made_young, + (buf_pool->stat.n_pages_made_young + - buf_pool->old_stat.n_pages_made_young) + / time_elapsed, + (buf_pool->stat.n_pages_not_made_young + - buf_pool->old_stat.n_pages_not_made_young) + / time_elapsed, + (ulong) buf_pool->stat.n_pages_read, + (ulong) buf_pool->stat.n_pages_created, + (ulong) buf_pool->stat.n_pages_written, + (buf_pool->stat.n_pages_read + - buf_pool->old_stat.n_pages_read) / time_elapsed, - (buf_pool->n_pages_created - buf_pool->n_pages_created_old) + (buf_pool->stat.n_pages_created + - buf_pool->old_stat.n_pages_created) / time_elapsed, - (buf_pool->n_pages_written - buf_pool->n_pages_written_old) + (buf_pool->stat.n_pages_written + - buf_pool->old_stat.n_pages_written) / time_elapsed); - if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) { - fprintf(file, "Buffer pool hit rate %lu / 1000\n", + n_gets_diff = buf_pool->stat.n_page_gets - buf_pool->old_stat.n_page_gets; + + if (n_gets_diff) { + fprintf(file, + "Buffer pool hit rate %lu / 1000," + " young-making rate %lu / 1000 not %lu / 1000\n", + (ulong) + (1000 - ((1000 * (buf_pool->stat.n_pages_read + - buf_pool->old_stat.n_pages_read)) + / (buf_pool->stat.n_page_gets + - buf_pool->old_stat.n_page_gets))), + (ulong) + (1000 * (buf_pool->stat.n_pages_made_young + - buf_pool->old_stat.n_pages_made_young) + / n_gets_diff), (ulong) - (1000 - ((1000 * (buf_pool->n_pages_read - - buf_pool->n_pages_read_old)) - / (buf_pool->n_page_gets - - buf_pool->n_page_gets_old)))); + (1000 * (buf_pool->stat.n_pages_not_made_young + - buf_pool->old_stat.n_pages_not_made_young) + / n_gets_diff)); } else { fputs("No buffer pool page gets since the last printout\n", file); } - buf_pool->n_page_gets_old = buf_pool->n_page_gets; - buf_pool->n_pages_read_old = buf_pool->n_pages_read; - buf_pool->n_pages_created_old = buf_pool->n_pages_created; - buf_pool->n_pages_written_old = buf_pool->n_pages_written; + /* Statistics about read ahead algorithm */ + fprintf(file, "Pages read ahead %.2f/s," + " evicted without access %.2f/s\n", + (buf_pool->stat.n_ra_pages_read + - buf_pool->old_stat.n_ra_pages_read) + / time_elapsed, + (buf_pool->stat.n_ra_pages_evicted + - buf_pool->old_stat.n_ra_pages_evicted) + / time_elapsed); /* Print some values to help us with visualizing what is happening with LRU eviction. */ @@ -3814,6 +3922,7 @@ buf_print_io( buf_LRU_stat_sum.io, buf_LRU_stat_cur.io, buf_LRU_stat_sum.unzip, buf_LRU_stat_cur.unzip); + buf_refresh_io_stats(); buf_pool_mutex_exit(); } @@ -3825,10 +3934,7 @@ buf_refresh_io_stats(void) /*======================*/ { buf_pool->last_printout_time = time(NULL); - buf_pool->n_page_gets_old = buf_pool->n_page_gets; - buf_pool->n_pages_read_old = buf_pool->n_pages_read; - buf_pool->n_pages_created_old = buf_pool->n_pages_created; - buf_pool->n_pages_written_old = buf_pool->n_pages_written; + buf_pool->old_stat = buf_pool->stat; } /*********************************************************************//** diff --git a/storage/innodb_plugin/buf/buf0flu.c b/storage/innodb_plugin/buf/buf0flu.c index 74dd0c07ca6..8b614ce90e5 100644 --- a/storage/innodb_plugin/buf/buf0flu.c +++ b/storage/innodb_plugin/buf/buf0flu.c @@ -304,6 +304,28 @@ buf_flush_write_complete( } /********************************************************************//** +Flush a batch of writes to the datafiles that have already been +written by the OS. */ +static +void +buf_flush_sync_datafiles(void) +/*==========================*/ +{ + /* Wake possible simulated aio thread to actually post the + writes to the operating system */ + os_aio_simulated_wake_handler_threads(); + + /* Wait that all async writes to tablespaces have been posted to + the OS */ + os_aio_wait_until_no_pending_writes(); + + /* Now we flush the data to disk (for example, with fsync) */ + fil_flush_file_spaces(FIL_TABLESPACE); + + return; +} + +/********************************************************************//** Flushes possible buffered writes from the doublewrite memory buffer to disk, and also wakes up the aio thread if simulated aio is used. It is very important to call this function after a batch of writes has been posted, @@ -320,8 +342,8 @@ buf_flush_buffered_writes(void) ulint i; if (!srv_use_doublewrite_buf || trx_doublewrite == NULL) { - os_aio_simulated_wake_handler_threads(); - + /* Sync the writes to the disk. */ + buf_flush_sync_datafiles(); return; } @@ -529,22 +551,10 @@ flush: buf_LRU_stat_inc_io(); } - /* Wake possible simulated aio thread to actually post the - writes to the operating system */ - - os_aio_simulated_wake_handler_threads(); - - /* Wait that all async writes to tablespaces have been posted to - the OS */ - - os_aio_wait_until_no_pending_writes(); - - /* Now we flush the data to disk (for example, with fsync) */ - - fil_flush_file_spaces(FIL_TABLESPACE); + /* Sync the writes to the disk. */ + buf_flush_sync_datafiles(); /* We can now reuse the doublewrite memory buffer: */ - trx_doublewrite->first_free = 0; mutex_exit(&(trx_doublewrite->mutex)); diff --git a/storage/innodb_plugin/buf/buf0lru.c b/storage/innodb_plugin/buf/buf0lru.c index be53a5f5d9d..4f19fd13fa5 100644 --- a/storage/innodb_plugin/buf/buf0lru.c +++ b/storage/innodb_plugin/buf/buf0lru.c @@ -49,18 +49,22 @@ Created 11/5/1995 Heikki Tuuri #include "log0recv.h" #include "srv0srv.h" -/** The number of blocks from the LRU_old pointer onward, including the block -pointed to, must be 3/8 of the whole LRU list length, except that the -tolerance defined below is allowed. Note that the tolerance must be small -enough such that for even the BUF_LRU_OLD_MIN_LEN long LRU list, the -LRU_old pointer is not allowed to point to either end of the LRU list. */ +/** The number of blocks from the LRU_old pointer onward, including +the block pointed to, must be buf_LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV +of the whole LRU list length, except that the tolerance defined below +is allowed. Note that the tolerance must be small enough such that for +even the BUF_LRU_OLD_MIN_LEN long LRU list, the LRU_old pointer is not +allowed to point to either end of the LRU list. */ #define BUF_LRU_OLD_TOLERANCE 20 -/** The whole LRU list length is divided by this number to determine an -initial segment in buf_LRU_get_recent_limit */ - -#define BUF_LRU_INITIAL_RATIO 8 +/** The minimum amount of non-old blocks when the LRU_old list exists +(that is, when there are more than BUF_LRU_OLD_MIN_LEN blocks). +@see buf_LRU_old_adjust_len */ +#define BUF_LRU_NON_OLD_MIN_LEN 5 +#if BUF_LRU_NON_OLD_MIN_LEN >= BUF_LRU_OLD_MIN_LEN +# error "BUF_LRU_NON_OLD_MIN_LEN >= BUF_LRU_OLD_MIN_LEN" +#endif /** When dropping the search hash index entries before deleting an ibd file, we build a local array of pages belonging to that tablespace @@ -107,6 +111,15 @@ UNIV_INTERN buf_LRU_stat_t buf_LRU_stat_sum; /* @} */ +/** @name Heuristics for detecting index scan @{ */ +/** Reserve this much/BUF_LRU_OLD_RATIO_DIV of the buffer pool for +"old" blocks. Protected by buf_pool_mutex. */ +UNIV_INTERN uint buf_LRU_old_ratio; +/** Move blocks to "new" LRU list only if the first access was at +least this many milliseconds ago. Not protected by any mutex or latch. */ +UNIV_INTERN uint buf_LRU_old_threshold_ms; +/* @} */ + /******************************************************************//** Takes a block out of the LRU list and page hash table. If the block is compressed-only (BUF_BLOCK_ZIP_PAGE), @@ -428,42 +441,6 @@ next_page: } } -/******************************************************************//** -Gets the minimum LRU_position field for the blocks in an initial segment -(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not -guaranteed to be precise, because the ulint_clock may wrap around. -@return the limit; zero if could not determine it */ -UNIV_INTERN -ulint -buf_LRU_get_recent_limit(void) -/*==========================*/ -{ - const buf_page_t* bpage; - ulint len; - ulint limit; - - buf_pool_mutex_enter(); - - len = UT_LIST_GET_LEN(buf_pool->LRU); - - if (len < BUF_LRU_OLD_MIN_LEN) { - /* The LRU list is too short to do read-ahead */ - - buf_pool_mutex_exit(); - - return(0); - } - - bpage = UT_LIST_GET_FIRST(buf_pool->LRU); - - limit = buf_page_get_LRU_position(bpage); - len /= BUF_LRU_INITIAL_RATIO; - - buf_pool_mutex_exit(); - - return(limit > len ? (limit - len) : 0); -} - /********************************************************************//** Insert a compressed block into buf_pool->zip_clean in the LRU order. */ UNIV_INTERN @@ -594,6 +571,7 @@ buf_LRU_free_from_common_LRU_list( bpage = UT_LIST_GET_PREV(LRU, bpage), distance--) { enum buf_lru_free_block_status freed; + unsigned accessed; mutex_t* block_mutex = buf_page_get_mutex(bpage); @@ -601,11 +579,18 @@ buf_LRU_free_from_common_LRU_list( ut_ad(bpage->in_LRU_list); mutex_enter(block_mutex); + accessed = buf_page_is_accessed(bpage); freed = buf_LRU_free_block(bpage, TRUE, NULL); mutex_exit(block_mutex); switch (freed) { case BUF_LRU_FREED: + /* Keep track of pages that are evicted without + ever being accessed. This gives us a measure of + the effectiveness of readahead */ + if (!accessed) { + ++buf_pool->stat.n_ra_pages_evicted; + } return(TRUE); case BUF_LRU_NOT_FREED: @@ -953,8 +938,10 @@ buf_LRU_old_adjust_len(void) ut_a(buf_pool->LRU_old); ut_ad(buf_pool_mutex_own()); -#if 3 * (BUF_LRU_OLD_MIN_LEN / 8) <= BUF_LRU_OLD_TOLERANCE + 5 -# error "3 * (BUF_LRU_OLD_MIN_LEN / 8) <= BUF_LRU_OLD_TOLERANCE + 5" + ut_ad(buf_LRU_old_ratio >= BUF_LRU_OLD_RATIO_MIN); + ut_ad(buf_LRU_old_ratio <= BUF_LRU_OLD_RATIO_MAX); +#if BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN <= BUF_LRU_OLD_RATIO_DIV * (BUF_LRU_OLD_TOLERANCE + 5) +# error "BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN <= BUF_LRU_OLD_RATIO_DIV * (BUF_LRU_OLD_TOLERANCE + 5)" #endif #ifdef UNIV_LRU_DEBUG /* buf_pool->LRU_old must be the first item in the LRU list @@ -966,34 +953,39 @@ buf_LRU_old_adjust_len(void) || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old); #endif /* UNIV_LRU_DEBUG */ + old_len = buf_pool->LRU_old_len; + new_len = ut_min(UT_LIST_GET_LEN(buf_pool->LRU) + * buf_LRU_old_ratio / BUF_LRU_OLD_RATIO_DIV, + UT_LIST_GET_LEN(buf_pool->LRU) + - (BUF_LRU_OLD_TOLERANCE + + BUF_LRU_NON_OLD_MIN_LEN)); + for (;;) { - old_len = buf_pool->LRU_old_len; - new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8); + buf_page_t* LRU_old = buf_pool->LRU_old; - ut_ad(buf_pool->LRU_old->in_LRU_list); - ut_a(buf_pool->LRU_old); + ut_a(LRU_old); + ut_ad(LRU_old->in_LRU_list); #ifdef UNIV_LRU_DEBUG - ut_a(buf_pool->LRU_old->old); + ut_a(LRU_old->old); #endif /* UNIV_LRU_DEBUG */ /* Update the LRU_old pointer if necessary */ - if (old_len < new_len - BUF_LRU_OLD_TOLERANCE) { + if (old_len + BUF_LRU_OLD_TOLERANCE < new_len) { - buf_pool->LRU_old = UT_LIST_GET_PREV( - LRU, buf_pool->LRU_old); + buf_pool->LRU_old = LRU_old = UT_LIST_GET_PREV( + LRU, LRU_old); #ifdef UNIV_LRU_DEBUG - ut_a(!buf_pool->LRU_old->old); + ut_a(!LRU_old->old); #endif /* UNIV_LRU_DEBUG */ - buf_page_set_old(buf_pool->LRU_old, TRUE); - buf_pool->LRU_old_len++; + old_len = ++buf_pool->LRU_old_len; + buf_page_set_old(LRU_old, TRUE); } else if (old_len > new_len + BUF_LRU_OLD_TOLERANCE) { - buf_page_set_old(buf_pool->LRU_old, FALSE); - buf_pool->LRU_old = UT_LIST_GET_NEXT( - LRU, buf_pool->LRU_old); - buf_pool->LRU_old_len--; + buf_pool->LRU_old = UT_LIST_GET_NEXT(LRU, LRU_old); + old_len = --buf_pool->LRU_old_len; + buf_page_set_old(LRU_old, FALSE); } else { return; } @@ -1017,12 +1009,13 @@ buf_LRU_old_init(void) the adjust function to move the LRU_old pointer to the right position */ - bpage = UT_LIST_GET_FIRST(buf_pool->LRU); - - while (bpage != NULL) { + for (bpage = UT_LIST_GET_LAST(buf_pool->LRU); bpage != NULL; + bpage = UT_LIST_GET_PREV(LRU, bpage)) { ut_ad(bpage->in_LRU_list); - buf_page_set_old(bpage, TRUE); - bpage = UT_LIST_GET_NEXT(LRU, bpage); + ut_ad(buf_page_in_file(bpage)); + /* This loop temporarily violates the + assertions of buf_page_set_old(). */ + bpage->old = TRUE; } buf_pool->LRU_old = UT_LIST_GET_FIRST(buf_pool->LRU); @@ -1075,16 +1068,19 @@ buf_LRU_remove_block( if (UNIV_UNLIKELY(bpage == buf_pool->LRU_old)) { - /* Below: the previous block is guaranteed to exist, because - the LRU_old pointer is only allowed to differ by the - tolerance value from strict 3/8 of the LRU list length. */ + /* Below: the previous block is guaranteed to exist, + because the LRU_old pointer is only allowed to differ + by BUF_LRU_OLD_TOLERANCE from strict + buf_LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV of the LRU + list length. */ + buf_page_t* prev_bpage = UT_LIST_GET_PREV(LRU, bpage); - buf_pool->LRU_old = UT_LIST_GET_PREV(LRU, bpage); - ut_a(buf_pool->LRU_old); + ut_a(prev_bpage); #ifdef UNIV_LRU_DEBUG - ut_a(!buf_pool->LRU_old->old); + ut_a(!prev_bpage->old); #endif /* UNIV_LRU_DEBUG */ - buf_page_set_old(buf_pool->LRU_old, TRUE); + buf_pool->LRU_old = prev_bpage; + buf_page_set_old(prev_bpage, TRUE); buf_pool->LRU_old_len++; } @@ -1095,10 +1091,19 @@ buf_LRU_remove_block( buf_unzip_LRU_remove_block_if_needed(bpage); - /* If the LRU list is so short that LRU_old not defined, return */ + /* If the LRU list is so short that LRU_old is not defined, + clear the "old" flags and return */ if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) { + for (bpage = UT_LIST_GET_FIRST(buf_pool->LRU); bpage != NULL; + bpage = UT_LIST_GET_NEXT(LRU, bpage)) { + /* This loop temporarily violates the + assertions of buf_page_set_old(). */ + bpage->old = FALSE; + } + buf_pool->LRU_old = NULL; + buf_pool->LRU_old_len = 0; return; } @@ -1149,39 +1154,24 @@ buf_LRU_add_block_to_end_low( /*=========================*/ buf_page_t* bpage) /*!< in: control block */ { - buf_page_t* last_bpage; - ut_ad(buf_pool); ut_ad(bpage); ut_ad(buf_pool_mutex_own()); ut_a(buf_page_in_file(bpage)); - last_bpage = UT_LIST_GET_LAST(buf_pool->LRU); - - if (last_bpage) { - bpage->LRU_position = last_bpage->LRU_position; - } else { - bpage->LRU_position = buf_pool_clock_tic(); - } - ut_ad(!bpage->in_LRU_list); UT_LIST_ADD_LAST(LRU, buf_pool->LRU, bpage); ut_d(bpage->in_LRU_list = TRUE); - buf_page_set_old(bpage, TRUE); - - if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) { - - buf_pool->LRU_old_len++; - } - if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) { ut_ad(buf_pool->LRU_old); /* Adjust the length of the old block list if necessary */ + buf_page_set_old(bpage, TRUE); + buf_pool->LRU_old_len++; buf_LRU_old_adjust_len(); } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) { @@ -1190,6 +1180,8 @@ buf_LRU_add_block_to_end_low( defined: init it */ buf_LRU_old_init(); + } else { + buf_page_set_old(bpage, buf_pool->LRU_old != NULL); } /* If this is a zipped block with decompressed frame as well @@ -1222,7 +1214,6 @@ buf_LRU_add_block_low( UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, bpage); - bpage->LRU_position = buf_pool_clock_tic(); bpage->freed_page_clock = buf_pool->freed_page_clock; } else { #ifdef UNIV_LRU_DEBUG @@ -1237,23 +1228,17 @@ buf_LRU_add_block_low( UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, buf_pool->LRU_old, bpage); buf_pool->LRU_old_len++; - - /* We copy the LRU position field of the previous block - to the new block */ - - bpage->LRU_position = (buf_pool->LRU_old)->LRU_position; } ut_d(bpage->in_LRU_list = TRUE); - buf_page_set_old(bpage, old); - if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) { ut_ad(buf_pool->LRU_old); /* Adjust the length of the old block list if necessary */ + buf_page_set_old(bpage, old); buf_LRU_old_adjust_len(); } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) { @@ -1262,6 +1247,8 @@ buf_LRU_add_block_low( defined: init it */ buf_LRU_old_init(); + } else { + buf_page_set_old(bpage, buf_pool->LRU_old != NULL); } /* If this is a zipped block with decompressed frame as well @@ -1295,6 +1282,12 @@ buf_LRU_make_block_young( /*=====================*/ buf_page_t* bpage) /*!< in: control block */ { + ut_ad(buf_pool_mutex_own()); + + if (bpage->old) { + buf_pool->stat.n_pages_made_young++; + } + buf_LRU_remove_block(bpage); buf_LRU_add_block_low(bpage, FALSE); } @@ -1453,15 +1446,6 @@ alloc: buf_pool->LRU_old = b; } -#ifdef UNIV_LRU_DEBUG - ut_a(prev_b->old - || !UT_LIST_GET_NEXT(LRU, b) - || UT_LIST_GET_NEXT(LRU, b)->old); - } else { - ut_a(!prev_b->old - || !UT_LIST_GET_NEXT(LRU, b) - || !UT_LIST_GET_NEXT(LRU, b)->old); -#endif /* UNIV_LRU_DEBUG */ } lru_len = UT_LIST_GET_LEN(buf_pool->LRU); @@ -1477,6 +1461,11 @@ alloc: defined: init it */ buf_LRU_old_init(); } +#ifdef UNIV_LRU_DEBUG + /* Check that the "old" flag is consistent + in the block and its neighbours. */ + buf_page_set_old(b, buf_page_is_old(b)); +#endif /* UNIV_LRU_DEBUG */ } else { ut_d(b->in_LRU_list = FALSE); buf_LRU_add_block_low(b, buf_page_is_old(b)); @@ -1847,6 +1836,50 @@ buf_LRU_block_free_hashed_page( buf_LRU_block_free_non_file_page(block); } +/**********************************************************************//** +Updates buf_LRU_old_ratio. +@return updated old_pct */ +UNIV_INTERN +uint +buf_LRU_old_ratio_update( +/*=====================*/ + uint old_pct,/*!< in: Reserve this percentage of + the buffer pool for "old" blocks. */ + ibool adjust) /*!< in: TRUE=adjust the LRU list; + FALSE=just assign buf_LRU_old_ratio + during the initialization of InnoDB */ +{ + uint ratio; + + ratio = old_pct * BUF_LRU_OLD_RATIO_DIV / 100; + if (ratio < BUF_LRU_OLD_RATIO_MIN) { + ratio = BUF_LRU_OLD_RATIO_MIN; + } else if (ratio > BUF_LRU_OLD_RATIO_MAX) { + ratio = BUF_LRU_OLD_RATIO_MAX; + } + + if (adjust) { + buf_pool_mutex_enter(); + + if (ratio != buf_LRU_old_ratio) { + buf_LRU_old_ratio = ratio; + + if (UT_LIST_GET_LEN(buf_pool->LRU) + >= BUF_LRU_OLD_MIN_LEN) { + buf_LRU_old_adjust_len(); + } + } + + buf_pool_mutex_exit(); + } else { + buf_LRU_old_ratio = ratio; + } + + /* the reverse of + ratio = old_pct * BUF_LRU_OLD_RATIO_DIV / 100 */ + return((uint) (ratio * 100 / (double) BUF_LRU_OLD_RATIO_DIV + 0.5)); +} + /********************************************************************//** Update the historical stats that we are collecting for LRU eviction policy at the end of each interval. */ @@ -1896,7 +1929,6 @@ buf_LRU_validate(void) buf_block_t* block; ulint old_len; ulint new_len; - ulint LRU_pos; ut_ad(buf_pool); buf_pool_mutex_enter(); @@ -1905,7 +1937,11 @@ buf_LRU_validate(void) ut_a(buf_pool->LRU_old); old_len = buf_pool->LRU_old_len; - new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8); + new_len = ut_min(UT_LIST_GET_LEN(buf_pool->LRU) + * buf_LRU_old_ratio / BUF_LRU_OLD_RATIO_DIV, + UT_LIST_GET_LEN(buf_pool->LRU) + - (BUF_LRU_OLD_TOLERANCE + + BUF_LRU_NON_OLD_MIN_LEN)); ut_a(old_len >= new_len - BUF_LRU_OLD_TOLERANCE); ut_a(old_len <= new_len + BUF_LRU_OLD_TOLERANCE); } @@ -1936,28 +1972,24 @@ buf_LRU_validate(void) } if (buf_page_is_old(bpage)) { - old_len++; - } + const buf_page_t* prev + = UT_LIST_GET_PREV(LRU, bpage); + const buf_page_t* next + = UT_LIST_GET_NEXT(LRU, bpage); - if (buf_pool->LRU_old && (old_len == 1)) { - ut_a(buf_pool->LRU_old == bpage); - } + if (!old_len++) { + ut_a(buf_pool->LRU_old == bpage); + } else { + ut_a(!prev || buf_page_is_old(prev)); + } - LRU_pos = buf_page_get_LRU_position(bpage); + ut_a(!next || buf_page_is_old(next)); + } bpage = UT_LIST_GET_NEXT(LRU, bpage); - - if (bpage) { - /* If the following assert fails, it may - not be an error: just the buf_pool clock - has wrapped around */ - ut_a(LRU_pos >= buf_page_get_LRU_position(bpage)); - } } - if (buf_pool->LRU_old) { - ut_a(buf_pool->LRU_old_len == old_len); - } + ut_a(buf_pool->LRU_old_len == old_len); UT_LIST_VALIDATE(list, buf_page_t, buf_pool->free, ut_ad(ut_list_node_313->in_free_list)); @@ -2000,9 +2032,6 @@ buf_LRU_print(void) ut_ad(buf_pool); buf_pool_mutex_enter(); - fprintf(stderr, "Pool ulint clock %lu\n", - (ulong) buf_pool->ulint_clock); - bpage = UT_LIST_GET_FIRST(buf_pool->LRU); while (bpage != NULL) { @@ -2033,18 +2062,16 @@ buf_LRU_print(void) const byte* frame; case BUF_BLOCK_FILE_PAGE: frame = buf_block_get_frame((buf_block_t*) bpage); - fprintf(stderr, "\nLRU pos %lu type %lu" + fprintf(stderr, "\ntype %lu" " index id %lu\n", - (ulong) buf_page_get_LRU_position(bpage), (ulong) fil_page_get_type(frame), (ulong) ut_dulint_get_low( btr_page_get_index_id(frame))); break; case BUF_BLOCK_ZIP_PAGE: frame = bpage->zip.data; - fprintf(stderr, "\nLRU pos %lu type %lu size %lu" + fprintf(stderr, "\ntype %lu size %lu" " index id %lu\n", - (ulong) buf_page_get_LRU_position(bpage), (ulong) fil_page_get_type(frame), (ulong) buf_page_get_zip_size(bpage), (ulong) ut_dulint_get_low( @@ -2052,8 +2079,7 @@ buf_LRU_print(void) break; default: - fprintf(stderr, "\nLRU pos %lu !state %lu!\n", - (ulong) buf_page_get_LRU_position(bpage), + fprintf(stderr, "\n!state %lu!\n", (ulong) buf_page_get_state(bpage)); break; } diff --git a/storage/innodb_plugin/buf/buf0rea.c b/storage/innodb_plugin/buf/buf0rea.c index 319d6b2a522..dd98ea17eb5 100644 --- a/storage/innodb_plugin/buf/buf0rea.c +++ b/storage/innodb_plugin/buf/buf0rea.c @@ -38,14 +38,6 @@ Created 11/5/1995 Heikki Tuuri #include "srv0start.h" #include "srv0srv.h" -/** The size in blocks of the area where the random read-ahead algorithm counts -the accessed pages when deciding whether to read-ahead */ -#define BUF_READ_AHEAD_RANDOM_AREA BUF_READ_AHEAD_AREA - -/** There must be at least this many pages in buf_pool in the area to start -a random read-ahead */ -#define BUF_READ_AHEAD_RANDOM_THRESHOLD (1 + BUF_READ_AHEAD_RANDOM_AREA / 2) - /** The linear read-ahead area size */ #define BUF_READ_AHEAD_LINEAR_AREA BUF_READ_AHEAD_AREA @@ -62,7 +54,8 @@ flag is cleared and the x-lock released by an i/o-handler thread. @return 1 if a read request was queued, 0 if the page already resided in buf_pool, or if the page is in the doublewrite buffer blocks in which case it is never read into the pool, or if the tablespace does -not exist or is being dropped */ +not exist or is being dropped +@return 1 if read request is issued. 0 if it is not */ static ulint buf_read_page_low( @@ -165,174 +158,13 @@ buf_read_page_low( } /********************************************************************//** -Applies a random read-ahead in buf_pool if there are at least a threshold -value of accessed pages from the random read-ahead area. Does not read any -page, not even the one at the position (space, offset), if the read-ahead -mechanism is not activated. NOTE 1: the calling thread may own latches on -pages: to avoid deadlocks this function must be written such that it cannot -end up waiting for these latches! NOTE 2: the calling thread must want -access to the page given: this rule is set to prevent unintended read-aheads -performed by ibuf routines, a situation which could result in a deadlock if -the OS does not support asynchronous i/o. -@return number of page read requests issued; NOTE that if we read ibuf -pages, it may happen that the page at the given page number does not -get read even if we return a positive value! */ -static -ulint -buf_read_ahead_random( -/*==================*/ - ulint space, /*!< in: space id */ - ulint zip_size,/*!< in: compressed page size in bytes, or 0 */ - ulint offset) /*!< in: page number of a page which the current thread - wants to access */ -{ - ib_int64_t tablespace_version; - ulint recent_blocks = 0; - ulint count; - ulint LRU_recent_limit; - ulint ibuf_mode; - ulint low, high; - ulint err; - ulint i; - ulint buf_read_ahead_random_area; - - /* We have currently disabled random readahead */ - return(0); - - if (srv_startup_is_before_trx_rollback_phase) { - /* No read-ahead to avoid thread deadlocks */ - return(0); - } - - if (ibuf_bitmap_page(zip_size, offset) - || trx_sys_hdr_page(space, offset)) { - - /* If it is an ibuf bitmap page or trx sys hdr, we do - no read-ahead, as that could break the ibuf page access - order */ - - return(0); - } - - /* Remember the tablespace version before we ask te tablespace size - below: if DISCARD + IMPORT changes the actual .ibd file meanwhile, we - do not try to read outside the bounds of the tablespace! */ - - tablespace_version = fil_space_get_version(space); - - buf_read_ahead_random_area = BUF_READ_AHEAD_RANDOM_AREA; - - low = (offset / buf_read_ahead_random_area) - * buf_read_ahead_random_area; - high = (offset / buf_read_ahead_random_area + 1) - * buf_read_ahead_random_area; - if (high > fil_space_get_size(space)) { - - high = fil_space_get_size(space); - } - - /* Get the minimum LRU_position field value for an initial segment - of the LRU list, to determine which blocks have recently been added - to the start of the list. */ - - LRU_recent_limit = buf_LRU_get_recent_limit(); - - buf_pool_mutex_enter(); - - if (buf_pool->n_pend_reads - > buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) { - buf_pool_mutex_exit(); - - return(0); - } - - /* Count how many blocks in the area have been recently accessed, - that is, reside near the start of the LRU list. */ - - for (i = low; i < high; i++) { - const buf_page_t* bpage = buf_page_hash_get(space, i); - - if (bpage - && buf_page_is_accessed(bpage) - && (buf_page_get_LRU_position(bpage) > LRU_recent_limit)) { - - recent_blocks++; - - if (recent_blocks >= BUF_READ_AHEAD_RANDOM_THRESHOLD) { - - buf_pool_mutex_exit(); - goto read_ahead; - } - } - } - - buf_pool_mutex_exit(); - /* Do nothing */ - return(0); - -read_ahead: - /* Read all the suitable blocks within the area */ - - if (ibuf_inside()) { - ibuf_mode = BUF_READ_IBUF_PAGES_ONLY; - } else { - ibuf_mode = BUF_READ_ANY_PAGE; - } - - count = 0; - - for (i = low; i < high; i++) { - /* It is only sensible to do read-ahead in the non-sync aio - mode: hence FALSE as the first parameter */ - - if (!ibuf_bitmap_page(zip_size, i)) { - count += buf_read_page_low( - &err, FALSE, - ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER, - space, zip_size, FALSE, - tablespace_version, i); - if (err == DB_TABLESPACE_DELETED) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Warning: in random" - " readahead trying to access\n" - "InnoDB: tablespace %lu page %lu,\n" - "InnoDB: but the tablespace does not" - " exist or is just being dropped.\n", - (ulong) space, (ulong) i); - } - } - } - - /* In simulated aio we wake the aio handler threads only after - queuing all aio requests, in native aio the following call does - nothing: */ - - os_aio_simulated_wake_handler_threads(); - -#ifdef UNIV_DEBUG - if (buf_debug_prints && (count > 0)) { - fprintf(stderr, - "Random read-ahead space %lu offset %lu pages %lu\n", - (ulong) space, (ulong) offset, - (ulong) count); - } -#endif /* UNIV_DEBUG */ - - ++srv_read_ahead_rnd; - return(count); -} - -/********************************************************************//** High-level function which reads a page asynchronously from a file to the buffer buf_pool if it is not already there. Sets the io_fix flag and sets an exclusive lock on the buffer frame. The flag is cleared and the x-lock -released by the i/o-handler thread. Does a random read-ahead if it seems -sensible. -@return number of page read requests issued: this can be greater than -1 if read-ahead occurred */ +released by the i/o-handler thread. +@return TRUE if page has been read in, FALSE in case of failure */ UNIV_INTERN -ulint +ibool buf_read_page( /*==========*/ ulint space, /*!< in: space id */ @@ -341,20 +173,17 @@ buf_read_page( { ib_int64_t tablespace_version; ulint count; - ulint count2; ulint err; tablespace_version = fil_space_get_version(space); - count = buf_read_ahead_random(space, zip_size, offset); - /* We do the i/o in the synchronous aio mode to save thread switches: hence TRUE */ - count2 = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space, - zip_size, FALSE, - tablespace_version, offset); - srv_buf_pool_reads+= count2; + count = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space, + zip_size, FALSE, + tablespace_version, offset); + srv_buf_pool_reads += count; if (err == DB_TABLESPACE_DELETED) { ut_print_timestamp(stderr); fprintf(stderr, @@ -371,14 +200,14 @@ buf_read_page( /* Increment number of I/O operations used for LRU policy. */ buf_LRU_stat_inc_io(); - return(count + count2); + return(count > 0); } /********************************************************************//** Applies linear read-ahead if in the buf_pool the page is a border page of a linear read-ahead area and all the pages in the area have been accessed. Does not read any page if the read-ahead mechanism is not activated. Note -that the the algorithm looks at the 'natural' adjacent successor and +that the algorithm looks at the 'natural' adjacent successor and predecessor of the page, which on the leaf level of a B-tree are the next and previous page in the chain of leaves. To know these, the page specified in (space, offset) must already be present in the buf_pool. Thus, the @@ -498,9 +327,17 @@ buf_read_ahead_linear( fail_count++; } else if (pred_bpage) { - int res = (ut_ulint_cmp( - buf_page_get_LRU_position(bpage), - buf_page_get_LRU_position(pred_bpage))); + /* Note that buf_page_is_accessed() returns + the time of the first access. If some blocks + of the extent existed in the buffer pool at + the time of a linear access pattern, the first + access times may be nonmonotonic, even though + the latest access times were linear. The + threshold (srv_read_ahead_factor) should help + a little against this. */ + int res = ut_ulint_cmp( + buf_page_is_accessed(bpage), + buf_page_is_accessed(pred_bpage)); /* Accesses not in the right order */ if (res != 0 && res != asc_or_desc) { fail_count++; @@ -643,7 +480,7 @@ buf_read_ahead_linear( LRU policy decision. */ buf_LRU_stat_inc_io(); - ++srv_read_ahead_seq; + buf_pool->stat.n_ra_pages_read += count; return(count); } diff --git a/storage/innodb_plugin/dict/dict0crea.c b/storage/innodb_plugin/dict/dict0crea.c index 7bad4d2057e..96a9bd8152e 100644 --- a/storage/innodb_plugin/dict/dict0crea.c +++ b/storage/innodb_plugin/dict/dict0crea.c @@ -1379,7 +1379,7 @@ dict_create_add_foreign_field_to_dictionary( Add a single foreign key definition to the data dictionary tables in the database. We also generate names to constraints that were not named by the user. A generated constraint has a name of the format -databasename/tablename_ibfk_<number>, where the numbers start from 1, and +databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and are given locally for this table, that is, the number is not global, as in the old format constraints < 4.0.18 it used to be. @return error code or DB_SUCCESS */ diff --git a/storage/innodb_plugin/dict/dict0dict.c b/storage/innodb_plugin/dict/dict0dict.c index d1f0e0ffc19..aedaf7cec1d 100644 --- a/storage/innodb_plugin/dict/dict0dict.c +++ b/storage/innodb_plugin/dict/dict0dict.c @@ -82,9 +82,10 @@ static char dict_ibfk[] = "_ibfk_"; /*******************************************************************//** Tries to find column names for the index and sets the col field of the -index. */ +index. +@return TRUE if the column names were found */ static -void +ibool dict_index_find_cols( /*=================*/ dict_table_t* table, /*!< in: table */ @@ -1169,7 +1170,7 @@ dict_col_name_is_reserved( ulint i; for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) { - if (strcmp(name, reserved_names[i]) == 0) { + if (innobase_strcasecmp(name, reserved_names[i]) == 0) { return(TRUE); } @@ -1431,7 +1432,7 @@ add_field_size: /**********************************************************************//** Adds an index to the dictionary cache. -@return DB_SUCCESS or DB_TOO_BIG_RECORD */ +@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */ UNIV_INTERN ulint dict_index_add_to_cache( @@ -1457,7 +1458,10 @@ dict_index_add_to_cache( ut_a(!dict_index_is_clust(index) || UT_LIST_GET_LEN(table->indexes) == 0); - dict_index_find_cols(table, index); + if (!dict_index_find_cols(table, index)) { + + return(DB_CORRUPTION); + } /* Build the cache internal representation of the index, containing also the added system fields */ @@ -1665,9 +1669,10 @@ dict_index_remove_from_cache( /*******************************************************************//** Tries to find column names for the index and sets the col field of the -index. */ +index. +@return TRUE if the column names were found */ static -void +ibool dict_index_find_cols( /*=================*/ dict_table_t* table, /*!< in: table */ @@ -1692,17 +1697,21 @@ dict_index_find_cols( } } +#ifdef UNIV_DEBUG /* It is an error not to find a matching column. */ fputs("InnoDB: Error: no matching column for ", stderr); ut_print_name(stderr, NULL, FALSE, field->name); fputs(" in ", stderr); dict_index_name_print(stderr, NULL, index); fputs("!\n", stderr); - ut_error; +#endif /* UNIV_DEBUG */ + return(FALSE); found: ; } + + return(TRUE); } #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innodb_plugin/fil/fil0fil.c b/storage/innodb_plugin/fil/fil0fil.c index 96e60b0128f..ba6f2f8666f 100644 --- a/storage/innodb_plugin/fil/fil0fil.c +++ b/storage/innodb_plugin/fil/fil0fil.c @@ -594,6 +594,11 @@ fil_node_create( UT_LIST_ADD_LAST(chain, space->chain, node); + if (id < SRV_LOG_SPACE_FIRST_ID && fil_system->max_assigned_id < id) { + + fil_system->max_assigned_id = id; + } + mutex_exit(&fil_system->mutex); } @@ -613,12 +618,10 @@ fil_node_open_file( ulint size_high; ibool ret; ibool success; -#ifndef UNIV_HOTBACKUP byte* buf2; byte* page; ulint space_id; ulint flags; -#endif /* !UNIV_HOTBACKUP */ ut_ad(mutex_own(&(system->mutex))); ut_a(node->n_pending == 0); @@ -654,9 +657,12 @@ fil_node_open_file( size_bytes = (((ib_int64_t)size_high) << 32) + (ib_int64_t)size_low; #ifdef UNIV_HOTBACKUP - node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE); - /* TODO: adjust to zip_size, like below? */ -#else + if (space->id == 0) { + node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE); + os_file_close(node->handle); + goto add_size; + } +#endif /* UNIV_HOTBACKUP */ ut_a(space->purpose != FIL_LOG); ut_a(space->id != 0); @@ -735,7 +741,10 @@ fil_node_open_file( (size_bytes / dict_table_flags_to_zip_size(flags)); } -#endif + +#ifdef UNIV_HOTBACKUP +add_size: +#endif /* UNIV_HOTBACKUP */ space->size += node->size; } @@ -955,7 +964,7 @@ close_more: " while the maximum\n" "InnoDB: allowed value would be %lu.\n" "InnoDB: You may need to raise the value of" - " innodb_max_files_open in\n" + " innodb_open_files in\n" "InnoDB: my.cnf.\n", (ulong) fil_system->n_open, (ulong) fil_system->max_n_open); @@ -1535,7 +1544,7 @@ fil_open_log_and_system_tablespace_files(void) fprintf(stderr, "InnoDB: Warning: you must" " raise the value of" - " innodb_max_open_files in\n" + " innodb_open_files in\n" "InnoDB: my.cnf! Remember that" " InnoDB keeps all log files" " and all system\n" @@ -2923,7 +2932,6 @@ fil_open_single_table_tablespace( byte* page; ulint space_id; ulint space_flags; - ibool ret = TRUE; filepath = fil_make_ibd_name(name, FALSE); @@ -3001,7 +3009,7 @@ fil_open_single_table_tablespace( (ulong) space_id, (ulong) space_flags, (ulong) id, (ulong) flags); - ret = FALSE; + success = FALSE; goto func_exit; } @@ -3021,7 +3029,7 @@ func_exit: os_file_close(file); mem_free(filepath); - return(ret); + return(success); } #endif /* !UNIV_HOTBACKUP */ @@ -3237,7 +3245,7 @@ fil_load_single_table_tablespace( fprintf(stderr, "InnoDB: Renaming tablespace %s of id %lu,\n" "InnoDB: to %s_ibbackup_old_vers_<timestamp>\n" - "InnoDB: because its size %lld is too small" + "InnoDB: because its size %" PRId64 " is too small" " (< 4 pages 16 kB each),\n" "InnoDB: or the space id in the file header" " is not sensible.\n" @@ -3299,7 +3307,17 @@ fil_load_single_table_tablespace( if (!success) { - goto func_exit; + if (srv_force_recovery > 0) { + fprintf(stderr, + "InnoDB: innodb_force_recovery" + " was set to %lu. Continuing crash recovery\n" + "InnoDB: even though the tablespace creation" + " of this table failed.\n", + srv_force_recovery); + goto func_exit; + } + + exit(1); } /* We do not use the size information we have about the file, because diff --git a/storage/innodb_plugin/fsp/fsp0fsp.c b/storage/innodb_plugin/fsp/fsp0fsp.c index ce14723ba18..3cc4318fc06 100644 --- a/storage/innodb_plugin/fsp/fsp0fsp.c +++ b/storage/innodb_plugin/fsp/fsp0fsp.c @@ -232,6 +232,9 @@ the extent are free and which contain old tuple version to clean. */ #define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE) #ifndef UNIV_HOTBACKUP +/* Flag to indicate if we have printed the tablespace full error. */ +static ibool fsp_tbs_full_error_printed = FALSE; + /**********************************************************************//** Returns an extent to the free list of a space. */ static @@ -1099,7 +1102,7 @@ fsp_header_inc_size( /**********************************************************************//** Gets the current free limit of the system tablespace. The free limit -means the place of the first page which has never been put to the the +means the place of the first page which has never been put to the free list for allocation. The space above that address is initialized to zero. Sets also the global variable log_fsp_current_free_limit. @return free limit in megabytes */ @@ -1218,6 +1221,19 @@ fsp_try_extend_data_file( if (space == 0 && !srv_auto_extend_last_data_file) { + /* We print the error message only once to avoid + spamming the error log. Note that we don't need + to reset the flag to FALSE as dealing with this + error requires server restart. */ + if (fsp_tbs_full_error_printed == FALSE) { + fprintf(stderr, + "InnoDB: Error: Data file(s) ran" + " out of space.\n" + "Please add another data file or" + " use \'autoextend\' for the last" + " data file.\n"); + fsp_tbs_full_error_printed = TRUE; + } return(FALSE); } @@ -1832,6 +1848,8 @@ fsp_seg_inode_page_find_used( if (!ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) { /* This is used */ + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); return(i); } } @@ -1863,6 +1881,9 @@ fsp_seg_inode_page_find_free( return(i); } + + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); } return(ULINT_UNDEFINED); @@ -1981,6 +2002,8 @@ fsp_alloc_seg_inode( page + FSEG_INODE_PAGE_NODE, mtr); } + ut_ad(ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID)) + || mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); return(inode); } @@ -2018,7 +2041,7 @@ fsp_free_seg_inode( } mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr); - mlog_write_ulint(inode + FSEG_MAGIC_N, 0, MLOG_4BYTES, mtr); + mlog_write_ulint(inode + FSEG_MAGIC_N, 0xfa051ce3, MLOG_4BYTES, mtr); if (ULINT_UNDEFINED == fsp_seg_inode_page_find_used(page, zip_size, mtr)) { @@ -2034,11 +2057,11 @@ fsp_free_seg_inode( /**********************************************************************//** Returns the file segment inode, page x-latched. -@return segment inode, page x-latched */ +@return segment inode, page x-latched; NULL if the inode is free */ static fseg_inode_t* -fseg_inode_get( -/*===========*/ +fseg_inode_try_get( +/*===============*/ fseg_header_t* header, /*!< in: segment header */ ulint space, /*!< in: space id */ ulint zip_size,/*!< in: compressed page size in bytes @@ -2054,12 +2077,38 @@ fseg_inode_get( inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr); - ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); + if (UNIV_UNLIKELY + (ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID)))) { + + inode = NULL; + } else { + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); + } return(inode); } /**********************************************************************//** +Returns the file segment inode, page x-latched. +@return segment inode, page x-latched */ +static +fseg_inode_t* +fseg_inode_get( +/*===========*/ + fseg_header_t* header, /*!< in: segment header */ + ulint space, /*!< in: space id */ + ulint zip_size,/*!< in: compressed page size in bytes + or 0 for uncompressed pages */ + mtr_t* mtr) /*!< in: mtr handle */ +{ + fseg_inode_t* inode + = fseg_inode_try_get(header, space, zip_size, mtr); + ut_a(inode); + return(inode); +} + +/**********************************************************************//** Gets the page number from the nth fragment page slot. @return page number, FIL_NULL if not in use */ UNIV_INLINE @@ -2073,6 +2122,7 @@ fseg_get_nth_frag_page_no( ut_ad(inode && mtr); ut_ad(n < FSEG_FRAG_ARR_N_SLOTS); ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); return(mach_read_from_4(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE)); } @@ -2091,6 +2141,7 @@ fseg_set_nth_frag_page_no( ut_ad(inode && mtr); ut_ad(n < FSEG_FRAG_ARR_N_SLOTS); ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX)); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE, page_no, MLOG_4BYTES, mtr); @@ -2451,6 +2502,8 @@ fseg_fill_free_list( xdes_set_state(descr, XDES_FSEG, mtr); seg_id = mtr_read_dulint(inode + FSEG_ID, mtr); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); mlog_write_dulint(descr + XDES_ID, seg_id, mtr); flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr); @@ -2479,6 +2532,7 @@ fseg_alloc_free_extent( fil_addr_t first; ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE)); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); if (flst_get_len(inode + FSEG_FREE, mtr) > 0) { /* Segment free list is not empty, allocate from it */ @@ -3136,6 +3190,8 @@ fseg_mark_page_used( ut_ad(seg_inode && mtr); ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE)); + ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); descr = xdes_get_descriptor(space, zip_size, page, mtr); @@ -3373,6 +3429,8 @@ fseg_free_extent( ut_a(xdes_get_state(descr, mtr) == XDES_FSEG); ut_a(0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, mtr), mtr_read_dulint(seg_inode + FSEG_ID, mtr))); + ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) + == FSEG_MAGIC_N_VALUE); first_page_in_extent = page - (page % FSP_EXTENT_SIZE); @@ -3463,7 +3521,13 @@ fseg_free_step( ut_a(descr); ut_a(xdes_get_bit(descr, XDES_FREE_BIT, header_page % FSP_EXTENT_SIZE, mtr) == FALSE); - inode = fseg_inode_get(header, space, zip_size, mtr); + inode = fseg_inode_try_get(header, space, zip_size, mtr); + + if (UNIV_UNLIKELY(inode == NULL)) { + fprintf(stderr, "double free of inode from %u:%u\n", + (unsigned) space, (unsigned) header_page); + return(TRUE); + } descr = fseg_get_first_extent(inode, space, zip_size, mtr); @@ -3587,6 +3651,7 @@ fseg_get_first_extent( ut_ad(inode && mtr); ut_ad(space == page_get_space_id(page_align(inode))); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); first = fil_addr_null; @@ -3801,6 +3866,7 @@ fseg_print_low( (ulong) reserved, (ulong) used, (ulong) n_full, (ulong) n_frag, (ulong) n_free, (ulong) n_not_full, (ulong) n_used); + ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); } #ifdef UNIV_BTR_PRINT diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 682004407c7..ac710ea2b15 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -72,6 +72,7 @@ with this program; if not, write to the Free Software Foundation, Inc., /* Include necessary InnoDB headers */ extern "C" { #include "univ.i" +#include "buf0lru.h" #include "btr0sea.h" #include "os0file.h" #include "os0thread.h" @@ -106,7 +107,10 @@ extern "C" { #include "i_s.h" #ifndef MYSQL_SERVER -/* This is needed because of Bug #3596. Let us hope that pthread_mutex_t +# ifndef MYSQL_PLUGIN_IMPORT +# define MYSQL_PLUGIN_IMPORT /* nothing */ +# endif /* MYSQL_PLUGIN_IMPORT */ +/* This is needed because of Bug #3596. Let us hope that pthread_mutex_t is defined the same in both builds: the MySQL server and the InnoDB plugin. */ extern MYSQL_PLUGIN_IMPORT pthread_mutex_t LOCK_thread_count; @@ -125,6 +129,7 @@ static ulong commit_threads = 0; static pthread_mutex_t commit_threads_m; static pthread_cond_t commit_cond; static pthread_mutex_t commit_cond_m; +static pthread_mutex_t analyze_mutex; static bool innodb_inited = 0; #define INSIDE_HA_INNOBASE_CC @@ -152,6 +157,10 @@ static ulong innobase_write_io_threads; static long long innobase_buffer_pool_size, innobase_log_file_size; +/** Percentage of the buffer pool to reserve for 'old' blocks. +Connected to buf_LRU_old_ratio. */ +static uint innobase_old_blocks_pct; + /* The default values for the following char* start-up parameters are determined in innobase_init below: */ @@ -166,9 +175,7 @@ file formats in the configuration file, but can only be set to any of the supported file formats during runtime. */ static char* innobase_file_format_check = NULL; -/* The following has a misleading name: starting from 4.0.5, this also -affects Windows: */ -static char* innobase_unix_file_flush_method = NULL; +static char* innobase_file_flush_method = NULL; /* Below we have boolean-valued start-up parameters, and their default values */ @@ -214,15 +221,19 @@ static void free_share(INNOBASE_SHARE *share); static int innobase_close_connection(handlerton *hton, THD* thd); static int innobase_commit(handlerton *hton, THD* thd, bool all); static int innobase_rollback(handlerton *hton, THD* thd, bool all); -static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, +static int innobase_rollback_to_savepoint(handlerton *hton, THD* thd, void *savepoint); static int innobase_savepoint(handlerton *hton, THD* thd, void *savepoint); -static int innobase_release_savepoint(handlerton *hton, THD* thd, +static int innobase_release_savepoint(handlerton *hton, THD* thd, void *savepoint); static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); +/* "GEN_CLUST_INDEX" is the name reserved for Innodb default +system primary index. */ +static const char innobase_index_reserve_name[]= "GEN_CLUST_INDEX"; + /** @brief Initialize the default value of innodb_commit_concurrency. Once InnoDB is running, the innodb_commit_concurrency must not change @@ -492,10 +503,10 @@ static SHOW_VAR innodb_status_variables[]= { (char*) &export_vars.innodb_buffer_pool_pages_misc, SHOW_LONG}, {"buffer_pool_pages_total", (char*) &export_vars.innodb_buffer_pool_pages_total, SHOW_LONG}, - {"buffer_pool_read_ahead_rnd", - (char*) &export_vars.innodb_buffer_pool_read_ahead_rnd, SHOW_LONG}, - {"buffer_pool_read_ahead_seq", - (char*) &export_vars.innodb_buffer_pool_read_ahead_seq, SHOW_LONG}, + {"buffer_pool_read_ahead", + (char*) &export_vars.innodb_buffer_pool_read_ahead, SHOW_LONG}, + {"buffer_pool_read_ahead_evicted", + (char*) &export_vars.innodb_buffer_pool_read_ahead_evicted, SHOW_LONG}, {"buffer_pool_read_requests", (char*) &export_vars.innodb_buffer_pool_read_requests, SHOW_LONG}, {"buffer_pool_reads", @@ -865,17 +876,14 @@ convert_error_code_to_mysql( return(ER_PRIMARY_CANT_HAVE_NULL); case DB_TOO_MANY_CONCURRENT_TRXS: - /* Once MySQL add the appropriate code to errmsg.txt then - we can get rid of this #ifdef. NOTE: The code checked by - the #ifdef is the suggested name for the error condition - and the actual error code name could very well be different. - This will require some monitoring, ie. the status - of this request on our part.*/ -#ifdef ER_TOO_MANY_CONCURRENT_TRXS - return(ER_TOO_MANY_CONCURRENT_TRXS); -#else + /* New error code HA_ERR_TOO_MANY_CONCURRENT_TRXS is only + available in 5.1.38 and later, but the plugin should still + work with previous versions of MySQL. */ +#ifdef HA_ERR_TOO_MANY_CONCURRENT_TRXS + return(HA_ERR_TOO_MANY_CONCURRENT_TRXS); +#else /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */ return(HA_ERR_RECORD_FILE_FULL); -#endif +#endif /* HA_ERR_TOO_MANY_CONCURRENT_TRXS */ case DB_UNSUPPORTED: return(HA_ERR_UNSUPPORTED); } @@ -949,7 +957,23 @@ innobase_get_cset_width( *mbminlen = cs->mbminlen; *mbmaxlen = cs->mbmaxlen; } else { - ut_a(cset == 0); + THD* thd = current_thd; + + if (thd && thd_sql_command(thd) == SQLCOM_DROP_TABLE) { + + /* Fix bug#46256: allow tables to be dropped if the + collation is not found, but issue a warning. */ + if ((global_system_variables.log_warnings) + && (cset != 0)){ + + sql_print_warning( + "Unknown collation #%lu.", cset); + } + } else { + + ut_a(cset == 0); + } + *mbminlen = *mbmaxlen = 0; } } @@ -2151,7 +2175,7 @@ innobase_change_buffering_inited_ok: /* --------------------------------------------------*/ - srv_file_flush_method_str = innobase_unix_file_flush_method; + srv_file_flush_method_str = innobase_file_flush_method; srv_n_log_groups = (ulint) innobase_mirrored_log_groups; srv_n_log_files = (ulint) innobase_log_files_in_group; @@ -2206,6 +2230,9 @@ innobase_change_buffering_inited_ok: ut_a(0 == strcmp(my_charset_latin1.name, "latin1_swedish_ci")); srv_latin1_ordering = my_charset_latin1.sort_order; + innobase_old_blocks_pct = buf_LRU_old_ratio_update( + innobase_old_blocks_pct, FALSE); + innobase_commit_concurrency_init_default(); /* Since we in this module access directly the fields of a trx @@ -2225,6 +2252,7 @@ innobase_change_buffering_inited_ok: pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST); pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST); pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST); + pthread_mutex_init(&analyze_mutex, MY_MUTEX_INIT_FAST); pthread_cond_init(&commit_cond, NULL); innodb_inited= 1; #ifdef MYSQL_DYNAMIC_PLUGIN @@ -2279,6 +2307,7 @@ innobase_end( pthread_mutex_destroy(&prepare_commit_mutex); pthread_mutex_destroy(&commit_threads_m); pthread_mutex_destroy(&commit_cond_m); + pthread_mutex_destroy(&analyze_mutex); pthread_cond_destroy(&commit_cond); } @@ -2459,6 +2488,19 @@ retry: } } + /* The following calls to read the MySQL binary log + file name and the position return consistent results: + 1) Other InnoDB transactions cannot intervene between + these calls as we are holding prepare_commit_mutex. + 2) Binary logging of other engines is not relevant + to InnoDB as all InnoDB requires is that committing + InnoDB transactions appear in the same order in the + MySQL binary log as they appear in InnoDB logs. + 3) A MySQL log file rotation cannot happen because + MySQL protects against this by having a counter of + transactions in prepared state and it only allows + a rotation when the counter drops to zero. See + LOCK_prep_xids and COND_prep_xids in log.cc. */ trx->mysql_log_file_name = mysql_bin_log_file_name(); trx->mysql_log_offset = (ib_int64_t) mysql_bin_log_file_pos(); @@ -2544,6 +2586,8 @@ innobase_rollback( innobase_release_stat_resources(trx); + trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */ + /* If we had reserved the auto-inc lock for some table (if we come here to roll back the latest SQL statement) we release it now before a possibly lengthy rollback */ @@ -3105,7 +3149,7 @@ retry: if (is_part) { sql_print_error("Failed to open table %s after " - "%lu attemtps.\n", norm_name, + "%lu attempts.\n", norm_name, retries); } @@ -3704,7 +3748,10 @@ ha_innobase::store_key_val_for_row( } else if (mysql_type == MYSQL_TYPE_TINY_BLOB || mysql_type == MYSQL_TYPE_MEDIUM_BLOB || mysql_type == MYSQL_TYPE_BLOB - || mysql_type == MYSQL_TYPE_LONG_BLOB) { + || mysql_type == MYSQL_TYPE_LONG_BLOB + /* MYSQL_TYPE_GEOMETRY data is treated + as BLOB data in innodb. */ + || mysql_type == MYSQL_TYPE_GEOMETRY) { CHARSET_INFO* cs; ulint key_len; @@ -5006,6 +5053,11 @@ ha_innobase::index_read( index = prebuilt->index; + if (UNIV_UNLIKELY(index == NULL)) { + prebuilt->index_usable = FALSE; + DBUG_RETURN(HA_ERR_CRASHED); + } + /* Note that if the index for which the search template is built is not necessarily prebuilt->index, but can also be the clustered index */ @@ -5165,6 +5217,7 @@ ha_innobase::change_active_index( if (UNIV_UNLIKELY(!prebuilt->index)) { sql_print_warning("InnoDB: change_active_index(%u) failed", keynr); + prebuilt->index_usable = FALSE; DBUG_RETURN(1); } @@ -5628,7 +5681,7 @@ create_table_def( number fits in one byte in prtype */ push_warning_printf( (THD*) trx->mysql_thd, - MYSQL_ERROR::WARN_LEVEL_ERROR, + MYSQL_ERROR::WARN_LEVEL_WARN, ER_CANT_CREATE_TABLE, "In InnoDB, charset-collation codes" " must be below 256." @@ -5657,6 +5710,28 @@ create_table_def( } } + /* First check whether the column to be added has a + system reserved name. */ + if (dict_col_name_is_reserved(field->field_name)){ + push_warning_printf( + (THD*) trx->mysql_thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_CREATE_TABLE, + "Error creating table '%s' with " + "column name '%s'. '%s' is a " + "reserved name. Please try to " + "re-create the table with a " + "different column name.", + table->name, (char*) field->field_name, + (char*) field->field_name); + + dict_mem_table_free(table); + trx_commit_for_mysql(trx); + + error = DB_ERROR; + goto error_ret; + } + dict_mem_table_add_col(table, table->heap, (char*) field->field_name, col_type, @@ -5670,6 +5745,7 @@ create_table_def( error = row_create_table_for_mysql(table, trx); +error_ret: error = convert_error_code_to_mysql(error, flags, NULL); DBUG_RETURN(error); @@ -5708,6 +5784,9 @@ create_index( n_fields = key->key_parts; + /* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */ + ut_a(innobase_strcasecmp(key->name, innobase_index_reserve_name) != 0); + ind_type = 0; if (key_num == form->s->primary_key) { @@ -5816,8 +5895,8 @@ create_clustered_index_when_no_primary( /* We pass 0 as the space id, and determine at a lower level the space id where to store the table */ - - index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX", + index = dict_mem_index_create(table_name, + innobase_index_reserve_name, 0, DICT_CLUSTERED, 0); error = row_create_index_for_mysql(index, trx, NULL); @@ -5870,7 +5949,7 @@ create_options_are_valid( /* Valid value. */ break; default: - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, "InnoDB: invalid" " KEY_BLOCK_SIZE = %lu." @@ -5884,7 +5963,7 @@ create_options_are_valid( /* If KEY_BLOCK_SIZE was specified, check for its dependencies. */ if (kbs_specified && !srv_file_per_table) { - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, "InnoDB: KEY_BLOCK_SIZE" " requires innodb_file_per_table."); @@ -5892,7 +5971,7 @@ create_options_are_valid( } if (kbs_specified && srv_file_format < DICT_TF_FORMAT_ZIP) { - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, "InnoDB: KEY_BLOCK_SIZE" " requires innodb_file_format >" @@ -5916,7 +5995,7 @@ create_options_are_valid( if (!srv_file_per_table) { push_warning_printf( thd, - MYSQL_ERROR::WARN_LEVEL_ERROR, + MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, "InnoDB: ROW_FORMAT=%s" " requires innodb_file_per_table.", @@ -5928,7 +6007,7 @@ create_options_are_valid( if (srv_file_format < DICT_TF_FORMAT_ZIP) { push_warning_printf( thd, - MYSQL_ERROR::WARN_LEVEL_ERROR, + MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, "InnoDB: ROW_FORMAT=%s" " requires innodb_file_format >" @@ -5945,7 +6024,7 @@ create_options_are_valid( && form->s->row_type == ROW_TYPE_DYNAMIC) { push_warning_printf( thd, - MYSQL_ERROR::WARN_LEVEL_ERROR, + MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, "InnoDB: cannot specify" " ROW_FORMAT = DYNAMIC with" @@ -5969,7 +6048,7 @@ create_options_are_valid( if (kbs_specified) { push_warning_printf( thd, - MYSQL_ERROR::WARN_LEVEL_ERROR, + MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, "InnoDB: cannot specify" " ROW_FORMAT = %s with" @@ -5982,7 +6061,7 @@ create_options_are_valid( default: push_warning(thd, - MYSQL_ERROR::WARN_LEVEL_ERROR, + MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, "InnoDB: invalid ROW_FORMAT specifier."); ret = FALSE; @@ -6046,13 +6125,15 @@ ha_innobase::create( 1. <database_name>/<table_name>: for normal table creation 2. full path: for temp table creation, or sym link - When srv_file_per_table is on, check for full path pattern, i.e. + When srv_file_per_table is on and mysqld_embedded is off, + check for full path pattern, i.e. X:\dir\..., X is a driver letter, or \\dir1\dir2\..., UNC path returns error if it is in full path format, but not creating a temp. table. Currently InnoDB does not support symbolic link on Windows. */ if (srv_file_per_table + && !mysqld_embedded && (!create_info->options & HA_LEX_CREATE_TMP_TABLE)) { if ((name[1] == ':') @@ -6243,14 +6324,6 @@ ha_innobase::create( flags = DICT_TF_COMPACT; } - error = create_table_def(trx, form, norm_name, - create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, - flags); - - if (error) { - goto cleanup; - } - /* Look for a primary key */ primary_key_no= (form->s->primary_key != MAX_KEY ? @@ -6262,6 +6335,23 @@ ha_innobase::create( ut_a(primary_key_no == -1 || primary_key_no == 0); + /* Check for name conflicts (with reserved name) for + any user indices to be created. */ + if (innobase_index_name_is_reserved(trx, form->key_info, + form->s->keys)) { + error = -1; + goto cleanup; + } + + error = create_table_def(trx, form, norm_name, + create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, + flags); + + if (error) { + goto cleanup; + } + + /* Create the keys */ if (form->s->keys == 0 || primary_key_no == -1) { @@ -6335,18 +6425,22 @@ ha_innobase::create( setup at this stage and so we use thd. */ /* We need to copy the AUTOINC value from the old table if - this is an ALTER TABLE. */ + this is an ALTER TABLE or CREATE INDEX because CREATE INDEX + does a table copy too. */ if (((create_info->used_fields & HA_CREATE_USED_AUTO) - || thd_sql_command(thd) == SQLCOM_ALTER_TABLE) - && create_info->auto_increment_value != 0) { - - /* Query was ALTER TABLE...AUTO_INCREMENT = x; or - CREATE TABLE ...AUTO_INCREMENT = x; Find out a table - definition from the dictionary and get the current value - of the auto increment field. Set a new value to the - auto increment field if the value is greater than the - maximum value in the column. */ + || thd_sql_command(thd) == SQLCOM_ALTER_TABLE + || thd_sql_command(thd) == SQLCOM_CREATE_INDEX) + && create_info->auto_increment_value > 0) { + + /* Query was one of : + CREATE TABLE ...AUTO_INCREMENT = x; or + ALTER TABLE...AUTO_INCREMENT = x; or + CREATE INDEX x on t(...); + Find out a table definition from the dictionary and get + the current value of the auto increment field. Set a new + value to the auto increment field if the value is greater + than the maximum value in the column. */ auto_inc_value = create_info->auto_increment_value; @@ -7200,9 +7294,15 @@ ha_innobase::analyze( THD* thd, /*!< in: connection thread handle */ HA_CHECK_OPT* check_opt) /*!< in: currently ignored */ { + /* Serialize ANALYZE TABLE inside InnoDB, see + Bug#38996 Race condition in ANALYZE TABLE */ + pthread_mutex_lock(&analyze_mutex); + /* Simply call ::info() with all the flags */ info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE); + pthread_mutex_unlock(&analyze_mutex); + return(0); } @@ -7797,8 +7897,9 @@ ha_innobase::external_lock( { ulong const binlog_format= thd_binlog_format(thd); ulong const tx_isolation = thd_tx_isolation(ha_thd()); - if (tx_isolation <= ISO_READ_COMMITTED && - binlog_format == BINLOG_FORMAT_STMT) + if (tx_isolation <= ISO_READ_COMMITTED + && binlog_format == BINLOG_FORMAT_STMT + && thd_binlog_filter_ok(thd)) { char buf[256]; my_snprintf(buf, sizeof(buf), @@ -8446,6 +8547,7 @@ ha_innobase::store_lock( && isolation_level != TRX_ISO_SERIALIZABLE && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) && (sql_command == SQLCOM_INSERT_SELECT + || sql_command == SQLCOM_REPLACE_SELECT || sql_command == SQLCOM_UPDATE || sql_command == SQLCOM_CREATE_TABLE)) { @@ -8453,10 +8555,11 @@ ha_innobase::store_lock( option set or this session is using READ COMMITTED isolation level and isolation level of the transaction is not set to serializable and MySQL is doing - INSERT INTO...SELECT or UPDATE ... = (SELECT ...) or - CREATE ... SELECT... without FOR UPDATE or - IN SHARE MODE in select, then we use consistent - read for select. */ + INSERT INTO...SELECT or REPLACE INTO...SELECT + or UPDATE ... = (SELECT ...) or CREATE ... + SELECT... without FOR UPDATE or IN SHARE + MODE in select, then we use consistent read + for select. */ prebuilt->select_lock_type = LOCK_NONE; prebuilt->stored_select_lock_type = LOCK_NONE; @@ -8676,6 +8779,7 @@ ha_innobase::get_auto_increment( AUTOINC counter after attempting to insert the row. */ if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) { ulonglong need; + ulonglong current; ulonglong next_value; ulonglong col_max_value; @@ -8684,11 +8788,12 @@ ha_innobase::get_auto_increment( col_max_value = innobase_get_int_col_max_value( table->next_number_field); + current = *first_value > col_max_value ? autoinc : *first_value; need = *nb_reserved_values * increment; /* Compute the last value in the interval */ next_value = innobase_next_autoinc( - *first_value, need, offset, col_max_value); + current, need, offset, col_max_value); prebuilt->autoinc_last_value = next_value; @@ -9612,6 +9717,25 @@ innodb_adaptive_hash_index_update( } } +/****************************************************************//** +Update the system variable innodb_old_blocks_pct using the "saved" +value. This function is registered as a callback with MySQL. */ +static +void +innodb_old_blocks_pct_update( +/*=========================*/ + THD* thd, /*!< in: thread handle */ + struct st_mysql_sys_var* var, /*!< in: pointer to + system variable */ + void* var_ptr,/*!< out: where the + formal string goes */ + const void* save) /*!< in: immediate result + from check function */ +{ + innobase_old_blocks_pct = buf_LRU_old_ratio_update( + *static_cast<const uint*>(save), TRUE); +} + /*************************************************************//** Check if it is a valid value of innodb_change_buffering. This function is registered as a callback with MySQL. @@ -9685,6 +9809,49 @@ static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff) return 0; } +/*********************************************************************** +This function checks each index name for a table against reserved +system default primary index name 'GEN_CLUST_INDEX'. If a name matches, +this function pushes an warning message to the client, and returns true. */ +extern "C" UNIV_INTERN +bool +innobase_index_name_is_reserved( +/*============================*/ + /* out: true if an index name + matches the reserved name */ + const trx_t* trx, /* in: InnoDB transaction handle */ + const KEY* key_info, /* in: Indexes to be created */ + ulint num_of_keys) /* in: Number of indexes to + be created. */ +{ + const KEY* key; + uint key_num; /* index number */ + + for (key_num = 0; key_num < num_of_keys; key_num++) { + key = &key_info[key_num]; + + if (innobase_strcasecmp(key->name, + innobase_index_reserve_name) == 0) { + /* Push warning to mysql */ + push_warning_printf((THD*) trx->mysql_thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WRONG_NAME_FOR_INDEX, + "Cannot Create Index with name " + "'%s'. The name is reserved " + "for the system default primary " + "index.", + innobase_index_reserve_name); + + my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), + innobase_index_reserve_name); + + return(true); + } + } + + return(false); +} + static SHOW_VAR innodb_status_variables_export[]= { {"Innodb", (char*) &show_innodb_vars, SHOW_FUNC}, {NullS, NullS, SHOW_LONG} @@ -9753,7 +9920,7 @@ static MYSQL_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit, " or 2 (write at commit, flush once per second).", NULL, NULL, 1, 0, 2, 0); -static MYSQL_SYSVAR_STR(flush_method, innobase_unix_file_flush_method, +static MYSQL_SYSVAR_STR(flush_method, innobase_file_flush_method, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "With which method to flush data.", NULL, NULL, NULL); @@ -9849,7 +10016,7 @@ static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter, NULL, NULL, 500L, 1L, ~0L, 0); static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads, - PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR, "Number of file I/O threads in InnoDB.", NULL, NULL, 4, 4, 64, 0); @@ -9888,6 +10055,18 @@ static MYSQL_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups, "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.", NULL, NULL, 1, 1, 10, 0); +static MYSQL_SYSVAR_UINT(old_blocks_pct, innobase_old_blocks_pct, + PLUGIN_VAR_RQCMDARG, + "Percentage of the buffer pool to reserve for 'old' blocks.", + NULL, innodb_old_blocks_pct_update, 100 * 3 / 8, 5, 95, 0); + +static MYSQL_SYSVAR_UINT(old_blocks_time, buf_LRU_old_threshold_ms, + PLUGIN_VAR_RQCMDARG, + "Move blocks to the 'new' end of the buffer pool if the first access" + " was at least this many milliseconds ago." + " The timeout is disabled if 0 (the default).", + NULL, NULL, 0, 0, UINT_MAX32, 0); + static MYSQL_SYSVAR_LONG(open_files, innobase_open_files, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "How many files at the maximum InnoDB keeps open at the same time.", @@ -9986,6 +10165,8 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(adaptive_flushing), MYSQL_SYSVAR(max_purge_lag), MYSQL_SYSVAR(mirrored_log_groups), + MYSQL_SYSVAR(old_blocks_pct), + MYSQL_SYSVAR(old_blocks_time), MYSQL_SYSVAR(open_files), MYSQL_SYSVAR(rollback_on_timeout), MYSQL_SYSVAR(stats_on_metadata), diff --git a/storage/innodb_plugin/handler/ha_innodb.h b/storage/innodb_plugin/handler/ha_innodb.h index cc98003f8ff..4779651ee27 100644 --- a/storage/innodb_plugin/handler/ha_innodb.h +++ b/storage/innodb_plugin/handler/ha_innodb.h @@ -257,6 +257,13 @@ int thd_binlog_format(const MYSQL_THD thd); @param all TRUE <=> rollback main transaction. */ void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); + +/** + Check if binary logging is filtered for thread's current db. + @param thd Thread handle + @retval 1 the query is not filtered, 0 otherwise. +*/ +bool thd_binlog_filter_ok(const MYSQL_THD thd); } typedef struct trx_struct trx_t; @@ -282,3 +289,21 @@ trx_t* innobase_trx_allocate( /*==================*/ MYSQL_THD thd); /*!< in: user thread handle */ + + +/*********************************************************************//** +This function checks each index name for a table against reserved +system default primary index name 'GEN_CLUST_INDEX'. If a name +matches, this function pushes an warning message to the client, +and returns true. */ +extern "C" +bool +innobase_index_name_is_reserved( +/*============================*/ + /* out: true if the index name + matches the reserved name */ + const trx_t* trx, /* in: InnoDB transaction handle */ + const KEY* key_info, /* in: Indexes to be created */ + ulint num_of_keys); /* in: Number of indexes to + be created. */ + diff --git a/storage/innodb_plugin/handler/handler0alter.cc b/storage/innodb_plugin/handler/handler0alter.cc index d1f64a1985c..37aed06b28a 100644 --- a/storage/innodb_plugin/handler/handler0alter.cc +++ b/storage/innodb_plugin/handler/handler0alter.cc @@ -628,7 +628,7 @@ ha_innobase::add_index( ulint num_created = 0; ibool dict_locked = FALSE; ulint new_primary; - ulint error; + int error; DBUG_ENTER("ha_innobase::add_index"); ut_a(table); @@ -656,14 +656,18 @@ ha_innobase::add_index( innodb_table = indexed_table = dict_table_get(prebuilt->table->name, FALSE); - /* Check that index keys are sensible */ - - error = innobase_check_index_keys(key_info, num_of_keys); + /* Check if the index name is reserved. */ + if (innobase_index_name_is_reserved(trx, key_info, num_of_keys)) { + error = -1; + } else { + /* Check that index keys are sensible */ + error = innobase_check_index_keys(key_info, num_of_keys); + } if (UNIV_UNLIKELY(error)) { err_exit: mem_heap_free(heap); - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx_free_for_mysql(trx); trx_commit_for_mysql(prebuilt->trx); DBUG_RETURN(error); @@ -801,7 +805,7 @@ error_handling: alter table t drop index b, add index (b); The fix will have to parse the SQL and note that the index - being added has the same name as the the one being dropped and + being added has the same name as the one being dropped and ignore that in the dup index check.*/ //dict_table_check_for_dup_indexes(prebuilt->table); #endif @@ -863,6 +867,7 @@ error_handling: indexed_table->n_mysql_handles_opened++; error = row_merge_drop_table(trx, innodb_table); + innodb_table = indexed_table; goto convert_error; case DB_TOO_BIG_RECORD: diff --git a/storage/innodb_plugin/handler/handler0vars.h b/storage/innodb_plugin/handler/handler0vars.h deleted file mode 100644 index e0f8f75e34d..00000000000 --- a/storage/innodb_plugin/handler/handler0vars.h +++ /dev/null @@ -1,69 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2008, 2009, Innobase Oy. 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 - -*****************************************************************************/ - -/*******************************************************************//** -@file handler/handler0vars.h -This file contains accessor functions for dynamic plugin on Windows. -***********************************************************************/ - -#if defined __WIN__ && defined MYSQL_DYNAMIC_PLUGIN -/*******************************************************************//** -This is a list of externals that can not be resolved by delay loading. -They have to be resolved indirectly via their addresses in the .map file. -All of them are external variables. */ -extern CHARSET_INFO* wdl_my_charset_bin; -extern CHARSET_INFO* wdl_my_charset_latin1; -extern CHARSET_INFO* wdl_my_charset_filename; -extern CHARSET_INFO** wdl_system_charset_info; -extern CHARSET_INFO** wdl_default_charset_info; -extern CHARSET_INFO** wdl_all_charsets; -extern system_variables* wdl_global_system_variables; -extern char* wdl_mysql_real_data_home; -extern char** wdl_mysql_data_home; -extern char** wdl_tx_isolation_names; -extern char** wdl_binlog_format_names; -extern char* wdl_reg_ext; -extern pthread_mutex_t* wdl_LOCK_thread_count; -extern key_map* wdl_key_map_full; -extern MY_TMPDIR* wdl_mysql_tmpdir_list; -extern bool* wdl_mysqld_embedded; -extern uint* wdl_lower_case_table_names; -extern ulong* wdl_specialflag; -extern int* wdl_my_umask; - -#define my_charset_bin (*wdl_my_charset_bin) -#define my_charset_latin1 (*wdl_my_charset_latin1) -#define my_charset_filename (*wdl_my_charset_filename) -#define system_charset_info (*wdl_system_charset_info) -#define default_charset_info (*wdl_default_charset_info) -#define all_charsets (wdl_all_charsets) -#define global_system_variables (*wdl_global_system_variables) -#define mysql_real_data_home (wdl_mysql_real_data_home) -#define mysql_data_home (*wdl_mysql_data_home) -#define tx_isolation_names (wdl_tx_isolation_names) -#define binlog_format_names (wdl_binlog_format_names) -#define reg_ext (wdl_reg_ext) -#define LOCK_thread_count (*wdl_LOCK_thread_count) -#define key_map_full (*wdl_key_map_full) -#define mysql_tmpdir_list (*wdl_mysql_tmpdir_list) -#define mysqld_embedded (*wdl_mysqld_embedded) -#define lower_case_table_names (*wdl_lower_case_table_names) -#define specialflag (*wdl_specialflag) -#define my_umask (*wdl_my_umask) - -#endif diff --git a/storage/innodb_plugin/handler/win_delay_loader.cc b/storage/innodb_plugin/handler/win_delay_loader.cc deleted file mode 100644 index 9b92f6a9cf2..00000000000 --- a/storage/innodb_plugin/handler/win_delay_loader.cc +++ /dev/null @@ -1,1024 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2008, 2009, Innobase Oy. 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 - -*****************************************************************************/ - -/*******************************************************************//** -@file handler/win_delay_loader.cc -This file contains functions that implement the delay loader on Windows. - -This is a customized version of delay loader with limited functionalities. -It does not support: - -* (manual) unloading -* multiple delay loaded DLLs -* multiple loading of the same DLL - -This delay loader is used only by the InnoDB plugin. Other components (DLLs) -can still use the default delay loader, provided by MSVC. - -Several acronyms used by Microsoft: - * IAT: import address table - * INT: import name table - * RVA: Relative Virtual Address - -See http://msdn.microsoft.com/en-us/magazine/bb985992.aspx for details of -PE format. -***********************************************************************/ -#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) -# define WIN32_LEAN_AND_MEAN -# include <windows.h> -# include <delayimp.h> -# include <mysql_priv.h> - -extern "C" { -# include "univ.i" -# include "hash0hash.h" -} - -/*******************************************************************//** -This following contains a list of externals that can not be resolved by -delay loading. They have to be resolved indirectly via their addresses -in the .map file. All of them are external variables. */ -CHARSET_INFO* wdl_my_charset_bin; -CHARSET_INFO* wdl_my_charset_latin1; -CHARSET_INFO* wdl_my_charset_filename; -CHARSET_INFO** wdl_system_charset_info; -CHARSET_INFO** wdl_default_charset_info; -CHARSET_INFO** wdl_all_charsets; -system_variables* wdl_global_system_variables; -char* wdl_mysql_real_data_home; -char** wdl_mysql_data_home; -char** wdl_tx_isolation_names; -char** wdl_binlog_format_names; -char* wdl_reg_ext; -pthread_mutex_t* wdl_LOCK_thread_count; -key_map* wdl_key_map_full; -MY_TMPDIR* wdl_mysql_tmpdir_list; -bool* wdl_mysqld_embedded; -uint* wdl_lower_case_table_names; -ulong* wdl_specialflag; -int* wdl_my_umask; - -/*******************************************************************//** -The preferred load-address defined in PE (portable executable format). */ -#if defined(_M_IA64) -#pragma section(".base", long, read) -extern "C" -__declspec(allocate(".base")) -const IMAGE_DOS_HEADER __ImageBase; -#else -extern "C" -const IMAGE_DOS_HEADER __ImageBase; -#endif - -/*******************************************************************//** -A template function for converting a relative address (RVA) to an -absolute address (VA). This is due to the pointers in the delay -descriptor (ImgDelayDescr in delayimp.h) have been changed from -VAs to RVAs to work on both 32- and 64-bit platforms. -@return absolute virtual address */ -template <class X> -X PFromRva( -/*=======*/ - RVA rva) /*!< in: relative virtual address */ -{ - return X(PBYTE(&__ImageBase) + rva); -} - -/*******************************************************************//** -Convert to the old format for convenience. The structure as well as its -element names follow the definition of ImgDelayDescr in delayimp.h. */ -struct InternalImgDelayDescr -{ - DWORD grAttrs; /*!< attributes */ - LPCSTR szName; /*!< pointer to dll name */ - HMODULE* phmod; /*!< address of module handle */ - PImgThunkData pIAT; /*!< address of the IAT */ - PCImgThunkData pINT; /*!< address of the INT */ - PCImgThunkData pBoundIAT; /*!< address of the optional bound IAT */ - PCImgThunkData pUnloadIAT; /*!< address of optional copy of - original IAT */ - DWORD dwTimeStamp; /*!< 0 if not bound, - otherwise date/time stamp of DLL - bound to (Old BIND) */ -}; - -typedef struct map_hash_chain_struct map_hash_chain_t; - -struct map_hash_chain_struct { - char* symbol; /*!< pointer to a symbol */ - ulint value; /*!< address of the symbol */ - map_hash_chain_t* next; /*!< pointer to the next cell - in the same folder. */ - map_hash_chain_t* chain; /*!< a linear chain used for - cleanup. */ -}; - -static HMODULE my_hmod = 0; -static struct hash_table_struct* m_htbl = NULL ; -static map_hash_chain_t* chain_header = NULL; -static ibool wdl_init = FALSE; -const ulint MAP_HASH_CELLS_NUM = 10000; - -#ifndef DBUG_OFF -/*******************************************************************//** -In the dynamic plugin, it is required to call the following dbug functions -in the server: - _db_pargs_ - _db_doprnt_ - _db_enter_ - _db_return_ - _db_dump_ - -The plugin will get those function pointers during the initialization. */ -typedef void (__cdecl* pfn_db_enter_)( - const char* _func_, - const char* _file_, - uint _line_, - const char** _sfunc_, - const char** _sfile_, - uint* _slevel_, - char***); - -typedef void (__cdecl* pfn_db_return_)( - uint _line_, - const char** _sfunc_, - const char** _sfile_, - uint* _slevel_); - -typedef void (__cdecl* pfn_db_pargs_)( - uint _line_, - const char* keyword); - -typedef void (__cdecl* pfn_db_doprnt_)( - const char* format, - ...); - -typedef void (__cdecl* pfn_db_dump_)( - uint _line_, - const char* keyword, - const unsigned char* memory, - size_t length); - -static pfn_db_enter_ wdl_db_enter_; -static pfn_db_return_ wdl_db_return_; -static pfn_db_pargs_ wdl_db_pargs_; -static pfn_db_doprnt_ wdl_db_doprnt_; -static pfn_db_dump_ wdl_db_dump_; -#endif /* !DBUG_OFF */ - -/*************************************************************//** -Creates a hash table with >= n array cells. The actual number of cells is -chosen to be a prime number slightly bigger than n. - -This is the same function as hash_create in hash0hash.c, except the -memory allocation. This function is invoked before the engine is -initialized, and buffer pools are not ready yet. -@return own: created hash table */ -static -hash_table_t* -wdl_hash_create( -/*============*/ - ulint n) /*!< in: number of array cells */ -{ - hash_cell_t* array; - ulint prime; - hash_table_t* table; - - prime = ut_find_prime(n); - - table = (hash_table_t*) malloc(sizeof(hash_table_t)); - if (table == NULL) { - return(NULL); - } - - array = (hash_cell_t*) malloc(sizeof(hash_cell_t) * prime); - if (array == NULL) { - free(table); - return(NULL); - } - - table->array = array; - table->n_cells = prime; - table->n_mutexes = 0; - table->mutexes = NULL; - table->heaps = NULL; - table->heap = NULL; - table->magic_n = HASH_TABLE_MAGIC_N; - - /* Initialize the cell array */ - hash_table_clear(table); - - return(table); -} - -/*************************************************************//** -Frees a hash table. */ -static -void -wdl_hash_table_free( -/*================*/ - hash_table_t* table) /*!< in, own: hash table */ -{ - ut_a(table != NULL); - ut_a(table->mutexes == NULL); - - free(table->array); - free(table); -} - -/*******************************************************************//** -Function for calculating the count of imports given the base of the IAT. -@return number of imports */ -static -ulint -wdl_import_count( -/*=============*/ - PCImgThunkData pitd_base) /*!< in: base of the IAT */ -{ - ulint ret = 0; - PCImgThunkData pitd = pitd_base; - - while (pitd->u1.Function) { - pitd++; - ret++; - } - - return(ret); -} - -/*******************************************************************//** -Read Mapfile to a hashtable for faster access -@return TRUE if the mapfile is loaded successfully. */ -static -ibool -wdl_load_mapfile( -/*=============*/ - const char* filename) /*!< in: name of the mapfile. */ -{ - FILE* fp; - const size_t nSize = 256; - char tmp_buf[nSize]; - char* func_name; - char* func_addr; - ulint load_addr = 0; - ibool valid_load_addr = FALSE; -#ifdef _WIN64 - const char* tmp_string = " Preferred load address is %16llx"; -#else - const char* tmp_string = " Preferred load address is %08x"; -#endif - - fp = fopen(filename, "r"); - if (fp == NULL) { - - return(FALSE); - } - - /* Check whether to create the hashtable */ - if (m_htbl == NULL) { - - m_htbl = wdl_hash_create(MAP_HASH_CELLS_NUM); - - if (m_htbl == NULL) { - - fclose(fp); - return(FALSE); - } - } - - /* Search start of symbol list and get the preferred load address */ - while (fgets(tmp_buf, sizeof(tmp_buf), fp)) { - - if (sscanf(tmp_buf, tmp_string, &load_addr) == 1) { - - valid_load_addr = TRUE; - } - - if (strstr(tmp_buf, "Rva+Base") != NULL) { - - break; - } - } - - if (valid_load_addr == FALSE) { - - /* No "Preferred load address", the map file is wrong. */ - fclose(fp); - return(FALSE); - } - - /* Read symbol list */ - while (fgets(tmp_buf, sizeof(tmp_buf), fp)) - { - map_hash_chain_t* map_cell; - ulint map_fold; - - if (*tmp_buf == 0) { - - continue; - } - - func_name = strtok(tmp_buf, " "); - func_name = strtok(NULL, " "); - func_addr = strtok(NULL, " "); - - if (func_name && func_addr) { - - ut_snprintf(tmp_buf, nSize, "0x%s", func_addr); - if (*func_name == '_') { - - func_name++; - } - - map_cell = (map_hash_chain_t*) - malloc(sizeof(map_hash_chain_t)); - if (map_cell == NULL) { - return(FALSE); - } - - /* Chain all cells together */ - map_cell->chain = chain_header; - chain_header = map_cell; - - map_cell->symbol = strdup(func_name); - map_cell->value = (ulint) _strtoui64(tmp_buf, NULL, 0) - - load_addr; - map_fold = ut_fold_string(map_cell->symbol); - - HASH_INSERT(map_hash_chain_t, - next, - m_htbl, - map_fold, - map_cell); - } - } - - fclose(fp); - - return(TRUE); -} - -/*************************************************************//** -Cleanup.during DLL unload */ -static -void -wdl_cleanup(void) -/*=============*/ -{ - while (chain_header != NULL) { - map_hash_chain_t* tmp; - - tmp = chain_header->chain; - free(chain_header->symbol); - free(chain_header); - chain_header = tmp; - } - - if (m_htbl != NULL) { - - wdl_hash_table_free(m_htbl); - } -} - -/*******************************************************************//** -Load the mapfile mysqld.map. -@return the module handle */ -static -HMODULE -wdl_get_mysqld_mapfile(void) -/*========================*/ -{ - char file_name[MAX_PATH]; - char* ext; - ulint err; - - if (my_hmod == 0) { - - size_t nSize = MAX_PATH - strlen(".map") -1; - - /* First find out the name of current executable */ - my_hmod = GetModuleHandle(NULL); - if (my_hmod == 0) { - - return(my_hmod); - } - - err = GetModuleFileName(my_hmod, file_name, nSize); - if (err == 0) { - - my_hmod = 0; - return(my_hmod); - } - - ext = strrchr(file_name, '.'); - if (ext != NULL) { - - *ext = 0; - strcat(file_name, ".map"); - - err = wdl_load_mapfile(file_name); - if (err == 0) { - - my_hmod = 0; - } - } else { - - my_hmod = 0; - } - } - - return(my_hmod); -} - -/*******************************************************************//** -Retrieves the address of an exported function. It follows the convention -of GetProcAddress(). -@return address of exported function. */ -static -FARPROC -wdl_get_procaddr_from_map( -/*======================*/ - HANDLE m_handle, /*!< in: module handle */ - const char* import_proc) /*!< in: procedure name */ -{ - map_hash_chain_t* hash_chain; - ulint map_fold; - - map_fold = ut_fold_string(import_proc); - HASH_SEARCH( - next, - m_htbl, - map_fold, - map_hash_chain_t*, - hash_chain, - , - (ut_strcmp(hash_chain->symbol, import_proc) == 0)); - - if (hash_chain == NULL) { - -#ifdef _WIN64 - /* On Win64, the leading '_' may not be taken out. In this - case, search again without the leading '_'. */ - if (*import_proc == '_') { - - import_proc++; - } - - map_fold = ut_fold_string(import_proc); - HASH_SEARCH( - next, - m_htbl, - map_fold, - map_hash_chain_t*, - hash_chain, - , - (ut_strcmp(hash_chain->symbol, import_proc) == 0)); - - if (hash_chain == NULL) { -#endif - if (wdl_init == TRUE) { - - sql_print_error( - "InnoDB: the procedure pointer of %s" - " is not found.", - import_proc); - } - - return(0); -#ifdef _WIN64 - } -#endif - } - - return((FARPROC) ((ulint) m_handle + hash_chain->value)); -} - -/*******************************************************************//** -Retrieves the address of an exported variable. -Note: It does not follow the Windows call convention FARPROC. -@return address of exported variable. */ -static -void* -wdl_get_varaddr_from_map( -/*=====================*/ - HANDLE m_handle, /*!< in: module handle */ - const char* import_variable) /*!< in: variable name */ -{ - map_hash_chain_t* hash_chain; - ulint map_fold; - - map_fold = ut_fold_string(import_variable); - HASH_SEARCH( - next, - m_htbl, - map_fold, - map_hash_chain_t*, - hash_chain, - , - (ut_strcmp(hash_chain->symbol, import_variable) == 0)); - - if (hash_chain == NULL) { - -#ifdef _WIN64 - /* On Win64, the leading '_' may not be taken out. In this - case, search again without the leading '_'. */ - if (*import_variable == '_') { - - import_variable++; - } - - map_fold = ut_fold_string(import_variable); - HASH_SEARCH( - next, - m_htbl, - map_fold, - map_hash_chain_t*, - hash_chain, - , - (ut_strcmp(hash_chain->symbol, import_variable) == 0)); - - if (hash_chain == NULL) { -#endif - if (wdl_init == TRUE) { - - sql_print_error( - "InnoDB: the variable address of %s" - " is not found.", - import_variable); - } - - return(0); -#ifdef _WIN64 - } -#endif - } - - return((void*) ((ulint) m_handle + hash_chain->value)); -} - -/*******************************************************************//** -Bind all unresolved external variables from the MySQL executable. -@return TRUE if successful */ -static -bool -wdl_get_external_variables(void) -/*============================*/ -{ - HMODULE hmod = wdl_get_mysqld_mapfile(); - - if (hmod == 0) { - - return(FALSE); - } - -#define GET_SYM(sym, var, type) \ - var = (type*) wdl_get_varaddr_from_map(hmod, sym); \ - if (var == NULL) return(FALSE) -#ifdef _WIN64 -#define GET_SYM2(sym1, sym2, var, type) \ - var = (type*) wdl_get_varaddr_from_map(hmod, sym1); \ - if (var == NULL) return(FALSE) -#else -#define GET_SYM2(sym1, sym2, var, type) \ - var = (type*) wdl_get_varaddr_from_map(hmod, sym2); \ - if (var == NULL) return(FALSE) -#endif // (_WIN64) -#define GET_C_SYM(sym, type) GET_SYM(#sym, wdl_##sym, type) -#define GET_PROC_ADDR(sym) \ - wdl##sym = (pfn##sym) wdl_get_procaddr_from_map(hmod, #sym) - - GET_C_SYM(my_charset_bin, CHARSET_INFO); - GET_C_SYM(my_charset_latin1, CHARSET_INFO); - GET_C_SYM(my_charset_filename, CHARSET_INFO); - GET_C_SYM(default_charset_info, CHARSET_INFO*); - GET_C_SYM(all_charsets, CHARSET_INFO*); - GET_C_SYM(my_umask, int); - - GET_SYM("?global_system_variables@@3Usystem_variables@@A", - wdl_global_system_variables, struct system_variables); - GET_SYM("?mysql_real_data_home@@3PADA", - wdl_mysql_real_data_home, char); - GET_SYM("?reg_ext@@3PADA", wdl_reg_ext, char); - GET_SYM("?LOCK_thread_count@@3U_RTL_CRITICAL_SECTION@@A", - wdl_LOCK_thread_count, pthread_mutex_t); - GET_SYM("?key_map_full@@3V?$Bitmap@$0EA@@@A", - wdl_key_map_full, key_map); - GET_SYM("?mysql_tmpdir_list@@3Ust_my_tmpdir@@A", - wdl_mysql_tmpdir_list, MY_TMPDIR); - GET_SYM("?mysqld_embedded@@3_NA", - wdl_mysqld_embedded, bool); - GET_SYM("?lower_case_table_names@@3IA", - wdl_lower_case_table_names, uint); - GET_SYM("?specialflag@@3KA", wdl_specialflag, ulong); - - GET_SYM2("?system_charset_info@@3PEAUcharset_info_st@@EA", - "?system_charset_info@@3PAUcharset_info_st@@A", - wdl_system_charset_info, CHARSET_INFO*); - GET_SYM2("?mysql_data_home@@3PEADEA", - "?mysql_data_home@@3PADA", - wdl_mysql_data_home, char*); - GET_SYM2("?tx_isolation_names@@3PAPEBDA", - "?tx_isolation_names@@3PAPBDA", - wdl_tx_isolation_names, char*); - GET_SYM2("?binlog_format_names@@3PAPEBDA", - "?binlog_format_names@@3PAPBDA", - wdl_binlog_format_names, char*); - -#ifndef DBUG_OFF - GET_PROC_ADDR(_db_enter_); - GET_PROC_ADDR(_db_return_); - GET_PROC_ADDR(_db_pargs_); - GET_PROC_ADDR(_db_doprnt_); - GET_PROC_ADDR(_db_dump_); - - /* If any of the dbug functions is not available, just make them - all invalid. This is the case when working with a non-debug - version of the server. */ - if (wdl_db_enter_ == NULL || wdl_db_return_ == NULL - || wdl_db_pargs_ == NULL || wdl_db_doprnt_ == NULL - || wdl_db_dump_ == NULL) { - - wdl_db_enter_ = NULL; - wdl_db_return_ = NULL; - wdl_db_pargs_ = NULL; - wdl_db_doprnt_ = NULL; - wdl_db_dump_ = NULL; - } -#endif /* !DBUG_OFF */ - - wdl_init = TRUE; - return(TRUE); - -#undef GET_SYM -#undef GET_SYM2 -#undef GET_C_SYM -#undef GET_PROC_ADDR -} - -/*******************************************************************//** -The DLL Delayed Loading Helper Function for resolving externals. - -The function may fail due to one of the three reasons: - -* Invalid parameter, which happens if the attributes in pidd aren't - specified correctly. -* Failed to load the map file mysqld.map. -* Failed to find an external name in the map file mysqld.map. - -Note: this function is called by run-time as well as __HrLoadAllImportsForDll. -So, it has to follow Windows call convention. -@return the address of the imported function */ -extern "C" -FARPROC WINAPI -__delayLoadHelper2( -/*===============*/ - PCImgDelayDescr pidd, /*!< in: a const pointer to a - ImgDelayDescr, see delayimp.h. */ - FARPROC* iat_entry) /*!< in/out: A pointer to the slot in - the delay load import address table - to be updated with the address of the - imported function. */ -{ - ulint iIAT, iINT; - HMODULE hmod; - PCImgThunkData pitd; - FARPROC fun = NULL; - - /* Set up data used for the hook procs */ - InternalImgDelayDescr idd = { - pidd->grAttrs, - PFromRva<LPCSTR>(pidd->rvaDLLName), - PFromRva<HMODULE*>(pidd->rvaHmod), - PFromRva<PImgThunkData>(pidd->rvaIAT), - PFromRva<PCImgThunkData>(pidd->rvaINT), - PFromRva<PCImgThunkData>(pidd->rvaBoundIAT), - PFromRva<PCImgThunkData>(pidd->rvaUnloadIAT), - pidd->dwTimeStamp - }; - - DelayLoadInfo dli = { - sizeof(DelayLoadInfo), - pidd, - iat_entry, - idd.szName, - {0}, - 0, - 0, - 0 - }; - - /* Check the Delay Load Attributes, log an error of invalid - parameter, which happens if the attributes in pidd are not - specified correctly. */ - if ((idd.grAttrs & dlattrRva) == 0) { - - sql_print_error("InnoDB: invalid parameter for delay loader."); - return(0); - } - - hmod = *idd.phmod; - - /* Calculate the index for the IAT entry in the import address table. - The INT entries are ordered the same as the IAT entries so the - calculation can be done on the IAT side. */ - iIAT = (PCImgThunkData) iat_entry - idd.pIAT; - iINT = iIAT; - - pitd = &(idd.pINT[iINT]); - - dli.dlp.fImportByName = !IMAGE_SNAP_BY_ORDINAL(pitd->u1.Ordinal); - - if (dli.dlp.fImportByName) { - - dli.dlp.szProcName = (LPCSTR) (PFromRva<PIMAGE_IMPORT_BY_NAME> - ((RVA) ((UINT_PTR) pitd->u1.AddressOfData))->Name); - } else { - - dli.dlp.dwOrdinal = (ulint) IMAGE_ORDINAL(pitd->u1.Ordinal); - } - - /* Now, load the mapfile, if it has not been done yet */ - if (hmod == 0) { - - hmod = wdl_get_mysqld_mapfile(); - } - - if (hmod == 0) { - /* LoadLibrary failed. */ - PDelayLoadInfo rgpdli[1] = {&dli}; - - dli.dwLastError = ::GetLastError(); - - sql_print_error( - "InnoDB: failed to load mysqld.map with error %d.", - dli.dwLastError); - - return(0); - } - - /* Store the library handle. */ - idd.phmod = &hmod; - - /* Go for the procedure now. */ - dli.hmodCur = hmod; - - if (pidd->rvaBoundIAT && pidd->dwTimeStamp) { - - /* Bound imports exist, check the timestamp from the target - image */ - PIMAGE_NT_HEADERS pinh; - - pinh = (PIMAGE_NT_HEADERS) ((byte*) hmod - + ((PIMAGE_DOS_HEADER) hmod)->e_lfanew); - - if (pinh->Signature == IMAGE_NT_SIGNATURE - && pinh->FileHeader.TimeDateStamp == idd.dwTimeStamp - && (DWORD) hmod == pinh->OptionalHeader.ImageBase) { - - /* We have a decent address in the bound IAT. */ - fun = (FARPROC) (UINT_PTR) - idd.pBoundIAT[iIAT].u1.Function; - - if (fun) { - - *iat_entry = fun; - return(fun); - } - } - } - - fun = wdl_get_procaddr_from_map(hmod, dli.dlp.szProcName); - - if (fun == 0) { - - return(0); - } - - *iat_entry = fun; - return(fun); -} - -/*******************************************************************//** -Unload a DLL that was delay loaded. This function is called by run-time. -@return TRUE is returned if the DLL is found and the IAT matches the -original one. */ -extern "C" -BOOL WINAPI -__FUnloadDelayLoadedDLL2( -/*=====================*/ - LPCSTR module_name) /*!< in: DLL name */ -{ - return(TRUE); -} - -/**************************************************************//** -Load all imports from a DLL that was specified with the /delayload linker -option. -Note: this function is called by run-time. So, it has to follow Windows call -convention. -@return S_OK if the DLL matches, otherwise ERROR_MOD_NOT_FOUND is returned. */ -extern "C" -HRESULT WINAPI -__HrLoadAllImportsForDll( -/*=====================*/ - LPCSTR module_name) /*!< in: DLL name */ -{ - PIMAGE_NT_HEADERS img; - PCImgDelayDescr pidd; - IMAGE_DATA_DIRECTORY* image_data; - LPCSTR current_module; - HRESULT ret = ERROR_MOD_NOT_FOUND; - HMODULE hmod = (HMODULE) &__ImageBase; - - img = (PIMAGE_NT_HEADERS) ((byte*) hmod - + ((PIMAGE_DOS_HEADER) hmod)->e_lfanew); - image_data = - &img->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT]; - - /* Scan the delay load IAT/INT for the DLL */ - if (image_data->Size) { - - pidd = PFromRva<PCImgDelayDescr>(image_data->VirtualAddress); - - /* Check all of the listed DLLs we want to load. */ - while (pidd->rvaDLLName) { - - current_module = PFromRva<LPCSTR>(pidd->rvaDLLName); - - if (stricmp(module_name, current_module) == 0) { - - /* Found it, break out with pidd and - current_module set appropriately */ - break; - } - - /* To the next delay import descriptor */ - pidd++; - } - - if (pidd->rvaDLLName) { - - /* Found a matching DLL, now process it. */ - FARPROC* iat_entry; - size_t count; - - iat_entry = PFromRva<FARPROC*>(pidd->rvaIAT); - count = wdl_import_count((PCImgThunkData) iat_entry); - - /* now load all the imports from the DLL */ - while (count > 0) { - - /* No need to check the return value */ - __delayLoadHelper2(pidd, iat_entry); - iat_entry++; - count--; - } - - ret = S_OK; - } - } - - return ret; -} - -/**************************************************************//** -The main function of a DLL -@return TRUE if the call succeeds */ -BOOL -WINAPI -DllMain( -/*====*/ - HINSTANCE hinstDLL, /*!< in: handle to the DLL module */ - DWORD fdwReason, /*!< Reason code that indicates why the - DLL entry-point function is being - called.*/ - LPVOID lpvReserved) /*!< in: additional parameter based on - fdwReason */ -{ - BOOL success = TRUE; - - switch (fdwReason) { - - case DLL_PROCESS_ATTACH: - success = wdl_get_external_variables(); - break; - - case DLL_PROCESS_DETACH: - wdl_cleanup(); - break; - } - - return(success); -} - -#ifndef DBUG_OFF -/**************************************************************//** -Process entry point to user function. It makes the call to _db_enter_ -in mysqld.exe. The DBUG functions are defined in my_dbug.h. */ -extern "C" UNIV_INTERN -void -_db_enter_( - const char* _func_, /*!< in: current function name */ - const char* _file_, /*!< in: current file name */ - uint _line_, /*!< in: current source line number */ - const char** _sfunc_, /*!< out: previous _func_ */ - const char** _sfile_, /*!< out: previous _file_ */ - uint* _slevel_, /*!< out: previous nesting level */ - char*** _sframep_) /*!< out: previous frame pointer */ -{ - if (wdl_db_enter_ != NULL) { - - wdl_db_enter_(_func_, _file_, _line_, _sfunc_, _sfile_, - _slevel_, _sframep_); - } -} - -/**************************************************************//** -Process exit from user function. It makes the call to _db_return_() -in the server. */ -extern "C" UNIV_INTERN -void -_db_return_( - uint _line_, /*!< in: current source line number */ - const char** _sfunc_, /*!< out: previous _func_ */ - const char** _sfile_, /*!< out: previous _file_ */ - uint* _slevel_) /*!< out: previous level */ -{ - if (wdl_db_return_ != NULL) { - - wdl_db_return_(_line_, _sfunc_, _sfile_, _slevel_); - } -} - -/**************************************************************//** -Log arguments for subsequent use. It makes the call to _db_pargs_() -in the server. */ -extern "C" UNIV_INTERN -void -_db_pargs_( - uint _line_, /*!< in: current source line number */ - const char* keyword) /*!< in: keyword for current macro */ -{ - if (wdl_db_pargs_ != NULL) { - - wdl_db_pargs_(_line_, keyword); - } -} - -/**************************************************************//** -Handle print of debug lines. It saves the text into a buffer first, -then makes the call to _db_doprnt_() in the server. The text is -truncated to the size of buffer. */ -extern "C" UNIV_INTERN -void -_db_doprnt_( - const char* format, /*!< in: the format string */ - ...) /*!< in: list of arguments */ -{ - va_list argp; - char buffer[512]; - - if (wdl_db_doprnt_ != NULL) { - - va_start(argp, format); - /* it is ok to ignore the trunction. */ - _vsnprintf(buffer, sizeof(buffer), format, argp); - wdl_db_doprnt_(buffer); - va_end(argp); - } -} - -/**************************************************************//** -Dump a string in hex. It makes the call to _db_dump_() in the server. */ -extern "C" UNIV_INTERN -void -_db_dump_( - uint _line_, /*!< in: current source line - number */ - const char* keyword, /*!< in: keyword list */ - const unsigned char* memory, /*!< in: memory to dump */ - size_t length) /*!< in: bytes to dump */ -{ - if (wdl_db_dump_ != NULL) { - - wdl_db_dump_(_line_, keyword, memory, length); - } -} - -#endif /* !DBUG_OFF */ -#endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */ diff --git a/storage/innodb_plugin/include/buf0buf.h b/storage/innodb_plugin/include/buf0buf.h index 65ad42c895a..927ff893e39 100644 --- a/storage/innodb_plugin/include/buf0buf.h +++ b/storage/innodb_plugin/include/buf0buf.h @@ -346,7 +346,7 @@ buf_page_release( mtr_t* mtr); /*!< in: mtr */ /********************************************************************//** Moves a page to the start of the buffer pool LRU list. This high-level -function can be used to prevent an important page from from slipping out of +function can be used to prevent an important page from slipping out of the buffer pool. */ UNIV_INTERN void @@ -707,15 +707,6 @@ buf_page_belongs_to_unzip_LRU( /*==========================*/ const buf_page_t* bpage) /*!< in: pointer to control block */ __attribute__((pure)); -/*********************************************************************//** -Determine the approximate LRU list position of a block. -@return LRU list position */ -UNIV_INLINE -ulint -buf_page_get_LRU_position( -/*======================*/ - const buf_page_t* bpage) /*!< in: control block */ - __attribute__((pure)); /*********************************************************************//** Gets the mutex of a block. @@ -816,14 +807,14 @@ buf_page_set_old( buf_page_t* bpage, /*!< in/out: control block */ ibool old); /*!< in: old */ /*********************************************************************//** -Determine if a block has been accessed in the buffer pool. -@return TRUE if accessed */ +Determine the time of first access of a block in the buffer pool. +@return ut_time_ms() at the time of first access, 0 if not accessed */ UNIV_INLINE -ibool +unsigned buf_page_is_accessed( /*=================*/ const buf_page_t* bpage) /*!< in: control block */ - __attribute__((pure)); + __attribute__((nonnull, pure)); /*********************************************************************//** Flag a block accessed. */ UNIV_INLINE @@ -831,7 +822,8 @@ void buf_page_set_accessed( /*==================*/ buf_page_t* bpage, /*!< in/out: control block */ - ibool accessed); /*!< in: accessed */ + ulint time_ms) /*!< in: ut_time_ms() */ + __attribute__((nonnull)); /*********************************************************************//** Gets the buf_block_t handle of a buffered file block if an uncompressed page frame exists, or NULL. @@ -1017,14 +1009,6 @@ buf_block_hash_get( /*===============*/ ulint space, /*!< in: space id */ ulint offset);/*!< in: offset of the page within space */ -/*******************************************************************//** -Increments the pool clock by one and returns its new value. Remember that -in the 32 bit version the clock wraps around at 4 billion! -@return new clock value */ -UNIV_INLINE -ulint -buf_pool_clock_tic(void); -/*====================*/ /*********************************************************************//** Gets the current length of the free list of buffer blocks. @return length of the free list */ @@ -1064,16 +1048,10 @@ struct buf_page_struct{ flushed to disk, this tells the flush_type. @see enum buf_flush */ - unsigned accessed:1; /*!< TRUE if the page has been accessed - while in the buffer pool: read-ahead - may read in pages which have not been - accessed yet; a thread is allowed to - read this for heuristic purposes - without holding any mutex or latch */ unsigned io_fix:2; /*!< type of pending I/O operation; also protected by buf_pool_mutex @see enum buf_io_fix */ - unsigned buf_fix_count:24;/*!< count of how manyfold this block + unsigned buf_fix_count:25;/*!< count of how manyfold this block is currently bufferfixed */ /* @} */ #endif /* !UNIV_HOTBACKUP */ @@ -1103,7 +1081,16 @@ struct buf_page_struct{ - BUF_BLOCK_FILE_PAGE: flush_list - BUF_BLOCK_ZIP_DIRTY: flush_list - BUF_BLOCK_ZIP_PAGE: zip_clean - - BUF_BLOCK_ZIP_FREE: zip_free[] */ + - BUF_BLOCK_ZIP_FREE: zip_free[] + + The contents of the list node + is undefined if !in_flush_list + && state == BUF_BLOCK_FILE_PAGE, + or if state is one of + BUF_BLOCK_MEMORY, + BUF_BLOCK_REMOVE_HASH or + BUF_BLOCK_READY_IN_USE. */ + #ifdef UNIV_DEBUG ibool in_flush_list; /*!< TRUE if in buf_pool->flush_list; when buf_pool_mutex is free, the @@ -1142,18 +1129,8 @@ struct buf_page_struct{ debugging */ #endif /* UNIV_DEBUG */ unsigned old:1; /*!< TRUE if the block is in the old - blocks in the LRU list */ - unsigned LRU_position:31;/*!< value which monotonically - decreases (or may stay - constant if old==TRUE) toward - the end of the LRU list, if - buf_pool->ulint_clock has not - wrapped around: NOTE that this - value can only be used in - heuristic algorithms, because - of the possibility of a - wrap-around! */ - unsigned freed_page_clock:32;/*!< the value of + blocks in buf_pool->LRU_old */ + unsigned freed_page_clock:31;/*!< the value of buf_pool->freed_page_clock when this block was the last time put to the head of the @@ -1161,6 +1138,9 @@ struct buf_page_struct{ to read this for heuristic purposes without holding any mutex or latch */ + unsigned access_time:32; /*!< time of first access, or + 0 if the block was never accessed + in the buffer pool */ /* @} */ # ifdef UNIV_DEBUG_FILE_ACCESSES ibool file_page_was_freed; @@ -1305,6 +1285,31 @@ Compute the hash fold value for blocks in buf_pool->zip_hash. */ #define BUF_POOL_ZIP_FOLD_BPAGE(b) BUF_POOL_ZIP_FOLD((buf_block_t*) (b)) /* @} */ +/** @brief The buffer pool statistics structure. */ +struct buf_pool_stat_struct{ + ulint n_page_gets; /*!< number of page gets performed; + also successful searches through + the adaptive hash index are + counted as page gets; this field + is NOT protected by the buffer + pool mutex */ + ulint n_pages_read; /*!< number read operations */ + ulint n_pages_written;/*!< number write operations */ + ulint n_pages_created;/*!< number of pages created + in the pool with no read */ + ulint n_ra_pages_read;/*!< number of pages read in + as part of read ahead */ + ulint n_ra_pages_evicted;/*!< number of read ahead + pages that are evicted without + being accessed */ + ulint n_pages_made_young; /*!< number of pages made young, in + calls to buf_LRU_make_block_young() */ + ulint n_pages_not_made_young; /*!< number of pages not made + young because the first access + was not long enough ago, in + buf_page_peek_if_too_old() */ +}; + /** @brief The buffer pool structure. NOTE! The definition appears here only for other modules of this @@ -1329,28 +1334,16 @@ struct buf_pool_struct{ ulint n_pend_reads; /*!< number of pending read operations */ ulint n_pend_unzip; /*!< number of pending decompressions */ - time_t last_printout_time; /*!< when buf_print was last time + time_t last_printout_time; + /*!< when buf_print_io was last time called */ - ulint n_pages_read; /*!< number read operations */ - ulint n_pages_written;/*!< number write operations */ - ulint n_pages_created;/*!< number of pages created - in the pool with no read */ - ulint n_page_gets; /*!< number of page gets performed; - also successful searches through - the adaptive hash index are - counted as page gets; this field - is NOT protected by the buffer - pool mutex */ - ulint n_page_gets_old;/*!< n_page_gets when buf_print was - last time called: used to calculate - hit rate */ - ulint n_pages_read_old;/*!< n_pages_read when buf_print was - last time called */ - ulint n_pages_written_old;/*!< number write operations */ - ulint n_pages_created_old;/*!< number of pages created in - the pool with no read */ + buf_pool_stat_t stat; /*!< current statistics */ + buf_pool_stat_t old_stat; /*!< old statistics */ + /* @} */ + /** @name Page flushing algorithm fields */ + /* @{ */ UT_LIST_BASE_NODE_T(buf_page_t) flush_list; @@ -1366,10 +1359,6 @@ struct buf_pool_struct{ /*!< this is in the set state when there is no flush batch of the given type running */ - ulint ulint_clock; /*!< a sequence number used to count - time. NOTE! This counter wraps - around at 4 billion (if ulint == - 32 bits)! */ ulint freed_page_clock;/*!< a sequence number used to count the number of buffer blocks removed from the end of @@ -1393,17 +1382,18 @@ struct buf_pool_struct{ block list */ UT_LIST_BASE_NODE_T(buf_page_t) LRU; /*!< base node of the LRU list */ - buf_page_t* LRU_old; /*!< pointer to the about 3/8 oldest - blocks in the LRU list; NULL if LRU - length less than BUF_LRU_OLD_MIN_LEN; + buf_page_t* LRU_old; /*!< pointer to the about + buf_LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV + oldest blocks in the LRU list; + NULL if LRU length less than + BUF_LRU_OLD_MIN_LEN; NOTE: when LRU_old != NULL, its length should always equal LRU_old_len */ ulint LRU_old_len; /*!< length of the LRU list from the block to which LRU_old points onward, including that block; see buf0lru.c for the restrictions - on this value; not defined if - LRU_old == NULL; + on this value; 0 if LRU_old == NULL; NOTE: LRU_old_len must be adjusted whenever LRU_old shrinks or grows! */ diff --git a/storage/innodb_plugin/include/buf0buf.ic b/storage/innodb_plugin/include/buf0buf.ic index 17064342116..0f92a59a1c7 100644 --- a/storage/innodb_plugin/include/buf0buf.ic +++ b/storage/innodb_plugin/include/buf0buf.ic @@ -72,9 +72,30 @@ buf_page_peek_if_too_old( /*=====================*/ const buf_page_t* bpage) /*!< in: block to make younger */ { - return(buf_pool->freed_page_clock - >= buf_page_get_freed_page_clock(bpage) - + 1 + (buf_pool->curr_size / 4)); + if (UNIV_UNLIKELY(buf_pool->freed_page_clock == 0)) { + /* If eviction has not started yet, do not update the + statistics or move blocks in the LRU list. This is + either the warm-up phase or an in-memory workload. */ + return(FALSE); + } else if (buf_LRU_old_threshold_ms && bpage->old) { + unsigned access_time = buf_page_is_accessed(bpage); + + if (access_time > 0 + && (ut_time_ms() - access_time) + >= buf_LRU_old_threshold_ms) { + return(TRUE); + } + + buf_pool->stat.n_pages_not_made_young++; + return(FALSE); + } else { + /* FIXME: bpage->freed_page_clock is 31 bits */ + return((buf_pool->freed_page_clock & ((1UL << 31) - 1)) + > ((ulint) bpage->freed_page_clock + + (buf_pool->curr_size + * (BUF_LRU_OLD_RATIO_DIV - buf_LRU_old_ratio) + / (BUF_LRU_OLD_RATIO_DIV * 4)))); + } } /*********************************************************************//** @@ -118,22 +139,6 @@ buf_pool_get_oldest_modification(void) return(lsn); } - -/*******************************************************************//** -Increments the buf_pool clock by one and returns its new value. Remember -that in the 32 bit version the clock wraps around at 4 billion! -@return new clock value */ -UNIV_INLINE -ulint -buf_pool_clock_tic(void) -/*====================*/ -{ - ut_ad(buf_pool_mutex_own()); - - buf_pool->ulint_clock++; - - return(buf_pool->ulint_clock); -} #endif /* !UNIV_HOTBACKUP */ /*********************************************************************//** @@ -280,21 +285,6 @@ buf_page_belongs_to_unzip_LRU( } /*********************************************************************//** -Determine the approximate LRU list position of a block. -@return LRU list position */ -UNIV_INLINE -ulint -buf_page_get_LRU_position( -/*======================*/ - const buf_page_t* bpage) /*!< in: control block */ -{ - ut_ad(buf_page_in_file(bpage)); - ut_ad(buf_pool_mutex_own()); - - return(bpage->LRU_position); -} - -/*********************************************************************//** Gets the mutex of a block. @return pointer to mutex protecting bpage */ UNIV_INLINE @@ -476,10 +466,19 @@ buf_page_set_old( ut_ad(bpage->in_LRU_list); #ifdef UNIV_LRU_DEBUG - if (UT_LIST_GET_PREV(LRU, bpage) && UT_LIST_GET_NEXT(LRU, bpage) - && UT_LIST_GET_PREV(LRU, bpage)->old - == UT_LIST_GET_NEXT(LRU, bpage)->old) { - ut_a(UT_LIST_GET_PREV(LRU, bpage)->old == old); + ut_a((buf_pool->LRU_old_len == 0) == (buf_pool->LRU_old == NULL)); + /* If a block is flagged "old", the LRU_old list must exist. */ + ut_a(!old || buf_pool->LRU_old); + + if (UT_LIST_GET_PREV(LRU, bpage) && UT_LIST_GET_NEXT(LRU, bpage)) { + const buf_page_t* prev = UT_LIST_GET_PREV(LRU, bpage); + const buf_page_t* next = UT_LIST_GET_NEXT(LRU, bpage); + if (prev->old == next->old) { + ut_a(prev->old == old); + } else { + ut_a(!prev->old); + ut_a(buf_pool->LRU_old == (old ? bpage : next)); + } } #endif /* UNIV_LRU_DEBUG */ @@ -487,17 +486,17 @@ buf_page_set_old( } /*********************************************************************//** -Determine if a block has been accessed in the buffer pool. -@return TRUE if accessed */ +Determine the time of first access of a block in the buffer pool. +@return ut_time_ms() at the time of first access, 0 if not accessed */ UNIV_INLINE -ibool +unsigned buf_page_is_accessed( /*=================*/ const buf_page_t* bpage) /*!< in: control block */ { ut_ad(buf_page_in_file(bpage)); - return(bpage->accessed); + return(bpage->access_time); } /*********************************************************************//** @@ -507,12 +506,15 @@ void buf_page_set_accessed( /*==================*/ buf_page_t* bpage, /*!< in/out: control block */ - ibool accessed) /*!< in: accessed */ + ulint time_ms) /*!< in: ut_time_ms() */ { ut_a(buf_page_in_file(bpage)); - ut_ad(mutex_own(buf_page_get_mutex(bpage))); + ut_ad(buf_pool_mutex_own()); - bpage->accessed = accessed; + if (!bpage->access_time) { + /* Make this the time of the first access. */ + bpage->access_time = time_ms; + } } /*********************************************************************//** diff --git a/storage/innodb_plugin/include/buf0lru.h b/storage/innodb_plugin/include/buf0lru.h index 463aca0982c..009430af35b 100644 --- a/storage/innodb_plugin/include/buf0lru.h +++ b/storage/innodb_plugin/include/buf0lru.h @@ -69,7 +69,7 @@ These are low-level functions #########################################################################*/ /** Minimum LRU list length for which the LRU_old pointer is defined */ -#define BUF_LRU_OLD_MIN_LEN 80 +#define BUF_LRU_OLD_MIN_LEN 512 /* 8 megabytes of 16k pages */ /** Maximum LRU list search length in buf_flush_LRU_recommendation() */ #define BUF_LRU_FREE_SEARCH_LEN (5 + 2 * BUF_READ_AHEAD_AREA) @@ -84,15 +84,6 @@ void buf_LRU_invalidate_tablespace( /*==========================*/ ulint id); /*!< in: space id */ -/******************************************************************//** -Gets the minimum LRU_position field for the blocks in an initial segment -(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not -guaranteed to be precise, because the ulint_clock may wrap around. -@return the limit; zero if could not determine it */ -UNIV_INTERN -ulint -buf_LRU_get_recent_limit(void); -/*==========================*/ /********************************************************************//** Insert a compressed block into buf_pool->zip_clean in the LRU order. */ UNIV_INTERN @@ -201,6 +192,18 @@ void buf_LRU_make_block_old( /*===================*/ buf_page_t* bpage); /*!< in: control block */ +/**********************************************************************//** +Updates buf_LRU_old_ratio. +@return updated old_pct */ +UNIV_INTERN +uint +buf_LRU_old_ratio_update( +/*=====================*/ + uint old_pct,/*!< in: Reserve this percentage of + the buffer pool for "old" blocks. */ + ibool adjust);/*!< in: TRUE=adjust the LRU list; + FALSE=just assign buf_LRU_old_ratio + during the initialization of InnoDB */ /********************************************************************//** Update the historical stats that we are collecting for LRU eviction policy at the end of each interval. */ @@ -227,6 +230,35 @@ buf_LRU_print(void); /*===============*/ #endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */ +/** @name Heuristics for detecting index scan @{ */ +/** Reserve this much/BUF_LRU_OLD_RATIO_DIV of the buffer pool for +"old" blocks. Protected by buf_pool_mutex. */ +extern uint buf_LRU_old_ratio; +/** The denominator of buf_LRU_old_ratio. */ +#define BUF_LRU_OLD_RATIO_DIV 1024 +/** Maximum value of buf_LRU_old_ratio. +@see buf_LRU_old_adjust_len +@see buf_LRU_old_ratio_update */ +#define BUF_LRU_OLD_RATIO_MAX BUF_LRU_OLD_RATIO_DIV +/** Minimum value of buf_LRU_old_ratio. +@see buf_LRU_old_adjust_len +@see buf_LRU_old_ratio_update +The minimum must exceed +(BUF_LRU_OLD_TOLERANCE + 5) * BUF_LRU_OLD_RATIO_DIV / BUF_LRU_OLD_MIN_LEN. */ +#define BUF_LRU_OLD_RATIO_MIN 51 + +#if BUF_LRU_OLD_RATIO_MIN >= BUF_LRU_OLD_RATIO_MAX +# error "BUF_LRU_OLD_RATIO_MIN >= BUF_LRU_OLD_RATIO_MAX" +#endif +#if BUF_LRU_OLD_RATIO_MAX > BUF_LRU_OLD_RATIO_DIV +# error "BUF_LRU_OLD_RATIO_MAX > BUF_LRU_OLD_RATIO_DIV" +#endif + +/** Move blocks to "new" LRU list only if the first access was at +least this many milliseconds ago. Not protected by any mutex or latch. */ +extern uint buf_LRU_old_threshold_ms; +/* @} */ + /** @brief Statistics for selecting the LRU list for eviction. These statistics are not 'of' LRU but 'for' LRU. We keep count of I/O diff --git a/storage/innodb_plugin/include/buf0rea.h b/storage/innodb_plugin/include/buf0rea.h index b4d25e6fde0..093750623d6 100644 --- a/storage/innodb_plugin/include/buf0rea.h +++ b/storage/innodb_plugin/include/buf0rea.h @@ -33,12 +33,10 @@ Created 11/5/1995 Heikki Tuuri High-level function which reads a page asynchronously from a file to the buffer buf_pool if it is not already there. Sets the io_fix flag and sets an exclusive lock on the buffer frame. The flag is cleared and the x-lock -released by the i/o-handler thread. Does a random read-ahead if it seems -sensible. -@return number of page read requests issued: this can be greater than -1 if read-ahead occurred */ +released by the i/o-handler thread. +@return TRUE if page has been read in, FALSE in case of failure */ UNIV_INTERN -ulint +ibool buf_read_page( /*==========*/ ulint space, /*!< in: space id */ @@ -48,7 +46,7 @@ buf_read_page( Applies linear read-ahead if in the buf_pool the page is a border page of a linear read-ahead area and all the pages in the area have been accessed. Does not read any page if the read-ahead mechanism is not activated. Note -that the the algorithm looks at the 'natural' adjacent successor and +that the algorithm looks at the 'natural' adjacent successor and predecessor of the page, which on the leaf level of a B-tree are the next and previous page in the chain of leaves. To know these, the page specified in (space, offset) must already be present in the buf_pool. Thus, the diff --git a/storage/innodb_plugin/include/buf0types.h b/storage/innodb_plugin/include/buf0types.h index e7167d716a0..bfae6477135 100644 --- a/storage/innodb_plugin/include/buf0types.h +++ b/storage/innodb_plugin/include/buf0types.h @@ -34,6 +34,8 @@ typedef struct buf_block_struct buf_block_t; typedef struct buf_chunk_struct buf_chunk_t; /** Buffer pool comprising buf_chunk_t */ typedef struct buf_pool_struct buf_pool_t; +/** Buffer pool statistics struct */ +typedef struct buf_pool_stat_struct buf_pool_stat_t; /** A buffer frame. @see page_t */ typedef byte buf_frame_t; diff --git a/storage/innodb_plugin/include/dict0crea.h b/storage/innodb_plugin/include/dict0crea.h index 3107d771d88..cce1246b789 100644 --- a/storage/innodb_plugin/include/dict0crea.h +++ b/storage/innodb_plugin/include/dict0crea.h @@ -110,7 +110,7 @@ dict_create_or_check_foreign_constraint_tables(void); Adds foreign key definitions to data dictionary tables in the database. We look at table->foreign_list, and also generate names to constraints that were not named by the user. A generated constraint has a name of the format -databasename/tablename_ibfk_<number>, where the numbers start from 1, and are +databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and are given locally for this table, that is, the number is not global, as in the old format constraints < 4.0.18 it used to be. @return error code or DB_SUCCESS */ diff --git a/storage/innodb_plugin/include/dict0dict.h b/storage/innodb_plugin/include/dict0dict.h index b2029699e51..d425241a3a2 100644 --- a/storage/innodb_plugin/include/dict0dict.h +++ b/storage/innodb_plugin/include/dict0dict.h @@ -712,7 +712,7 @@ dict_index_find_on_id_low( dulint id); /*!< in: index id */ /**********************************************************************//** Adds an index to the dictionary cache. -@return DB_SUCCESS or error code */ +@return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */ UNIV_INTERN ulint dict_index_add_to_cache( diff --git a/storage/innodb_plugin/include/dict0mem.h b/storage/innodb_plugin/include/dict0mem.h index 1ee906fbf57..2d001111938 100644 --- a/storage/innodb_plugin/include/dict0mem.h +++ b/storage/innodb_plugin/include/dict0mem.h @@ -317,7 +317,7 @@ struct dict_foreign_struct{ char* id; /*!< id of the constraint as a null-terminated string */ unsigned n_fields:10; /*!< number of indexes' first fields - for which the the foreign key + for which the foreign key constraint is defined: we allow the indexes to contain more fields than mentioned in the constraint, as long diff --git a/storage/innodb_plugin/include/fsp0fsp.h b/storage/innodb_plugin/include/fsp0fsp.h index 5f7dc58eedc..7abd3914eda 100644 --- a/storage/innodb_plugin/include/fsp0fsp.h +++ b/storage/innodb_plugin/include/fsp0fsp.h @@ -42,7 +42,7 @@ fsp_init(void); /*==========*/ /**********************************************************************//** Gets the current free limit of the system tablespace. The free limit -means the place of the first page which has never been put to the the +means the place of the first page which has never been put to the free list for allocation. The space above that address is initialized to zero. Sets also the global variable log_fsp_current_free_limit. @return free limit in megabytes */ diff --git a/storage/innodb_plugin/include/lock0lock.h b/storage/innodb_plugin/include/lock0lock.h index fa5db831d4f..aeabe39e1a9 100644 --- a/storage/innodb_plugin/include/lock0lock.h +++ b/storage/innodb_plugin/include/lock0lock.h @@ -630,6 +630,14 @@ lock_number_of_rows_locked( /*=======================*/ trx_t* trx); /*!< in: transaction */ /*******************************************************************//** +Check if a transaction holds any autoinc locks. +@return TRUE if the transaction holds any AUTOINC locks. */ +UNIV_INTERN +ibool +lock_trx_holds_autoinc_locks( +/*=========================*/ + const trx_t* trx); /*!< in: transaction */ +/*******************************************************************//** Release all the transaction's autoinc locks. */ UNIV_INTERN void diff --git a/storage/innodb_plugin/include/log0log.h b/storage/innodb_plugin/include/log0log.h index 059f548a085..299b4a05b40 100644 --- a/storage/innodb_plugin/include/log0log.h +++ b/storage/innodb_plugin/include/log0log.h @@ -118,10 +118,9 @@ UNIV_INLINE ib_uint64_t log_reserve_and_write_fast( /*=======================*/ - byte* str, /*!< in: string */ + const void* str, /*!< in: string */ ulint len, /*!< in: string length */ - ib_uint64_t* start_lsn,/*!< out: start lsn of the log record */ - ibool* success);/*!< out: TRUE if success */ + ib_uint64_t* start_lsn);/*!< out: start lsn of the log record */ /***********************************************************************//** Releases the log mutex. */ UNIV_INLINE @@ -283,7 +282,7 @@ log_make_checkpoint_at( later lsn, if IB_ULONGLONG_MAX, makes a checkpoint at the latest lsn */ ibool write_always); /*!< in: the function normally checks if - the the new checkpoint would have a + the new checkpoint would have a greater lsn than the previous one: if not, then no physical write is done; by setting this parameter TRUE, a diff --git a/storage/innodb_plugin/include/log0log.ic b/storage/innodb_plugin/include/log0log.ic index d071985982a..36d151a3064 100644 --- a/storage/innodb_plugin/include/log0log.ic +++ b/storage/innodb_plugin/include/log0log.ic @@ -27,6 +27,7 @@ Created 12/9/1995 Heikki Tuuri #include "mach0data.h" #include "mtr0mtr.h" +#ifdef UNIV_LOG_DEBUG /******************************************************//** Checks by parsing that the catenated log segment for a single mtr is consistent. */ @@ -34,11 +35,12 @@ UNIV_INTERN ibool log_check_log_recs( /*===============*/ - byte* buf, /*!< in: pointer to the start of + const byte* buf, /*!< in: pointer to the start of the log segment in the log_sys->buf log buffer */ ulint len, /*!< in: segment length in bytes */ ib_uint64_t buf_start_lsn); /*!< in: buffer start lsn */ +#endif /* UNIV_LOG_DEBUG */ /************************************************************//** Gets a log block flush bit. @@ -305,55 +307,76 @@ UNIV_INLINE ib_uint64_t log_reserve_and_write_fast( /*=======================*/ - byte* str, /*!< in: string */ + const void* str, /*!< in: string */ ulint len, /*!< in: string length */ - ib_uint64_t* start_lsn,/*!< out: start lsn of the log record */ - ibool* success)/*!< out: TRUE if success */ + ib_uint64_t* start_lsn)/*!< out: start lsn of the log record */ { - log_t* log = log_sys; ulint data_len; - ib_uint64_t lsn; +#ifdef UNIV_LOG_LSN_DEBUG + /* length of the LSN pseudo-record */ + ulint lsn_len = 1 + + mach_get_compressed_size(log_sys->lsn >> 32) + + mach_get_compressed_size(log_sys->lsn & 0xFFFFFFFFUL); +#endif /* UNIV_LOG_LSN_DEBUG */ - *success = TRUE; + mutex_enter(&log_sys->mutex); - mutex_enter(&(log->mutex)); - - data_len = len + log->buf_free % OS_FILE_LOG_BLOCK_SIZE; + data_len = len +#ifdef UNIV_LOG_LSN_DEBUG + + lsn_len +#endif /* UNIV_LOG_LSN_DEBUG */ + + log_sys->buf_free % OS_FILE_LOG_BLOCK_SIZE; if (data_len >= OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE) { /* The string does not fit within the current log block or the log block would become full */ - *success = FALSE; - - mutex_exit(&(log->mutex)); + mutex_exit(&log_sys->mutex); return(0); } - *start_lsn = log->lsn; - - ut_memcpy(log->buf + log->buf_free, str, len); + *start_lsn = log_sys->lsn; + +#ifdef UNIV_LOG_LSN_DEBUG + { + /* Write the LSN pseudo-record. */ + byte* b = &log_sys->buf[log_sys->buf_free]; + *b++ = MLOG_LSN | (MLOG_SINGLE_REC_FLAG & *(const byte*) str); + /* Write the LSN in two parts, + as a pseudo page number and space id. */ + b += mach_write_compressed(b, log_sys->lsn >> 32); + b += mach_write_compressed(b, log_sys->lsn & 0xFFFFFFFFUL); + ut_a(b - lsn_len == &log_sys->buf[log_sys->buf_free]); + + memcpy(b, str, len); + len += lsn_len; + } +#else /* UNIV_LOG_LSN_DEBUG */ + memcpy(log_sys->buf + log_sys->buf_free, str, len); +#endif /* UNIV_LOG_LSN_DEBUG */ - log_block_set_data_len((byte*) ut_align_down(log->buf + log->buf_free, + log_block_set_data_len((byte*) ut_align_down(log_sys->buf + + log_sys->buf_free, OS_FILE_LOG_BLOCK_SIZE), data_len); #ifdef UNIV_LOG_DEBUG - log->old_buf_free = log->buf_free; - log->old_lsn = log->lsn; + log_sys->old_buf_free = log_sys->buf_free; + log_sys->old_lsn = log_sys->lsn; #endif - log->buf_free += len; + log_sys->buf_free += len; - ut_ad(log->buf_free <= log->buf_size); + ut_ad(log_sys->buf_free <= log_sys->buf_size); - lsn = log->lsn += len; + log_sys->lsn += len; #ifdef UNIV_LOG_DEBUG - log_check_log_recs(log->buf + log->old_buf_free, - log->buf_free - log->old_buf_free, log->old_lsn); + log_check_log_recs(log_sys->buf + log_sys->old_buf_free, + log_sys->buf_free - log_sys->old_buf_free, + log_sys->old_lsn); #endif - return(lsn); + return(log_sys->lsn); } /***********************************************************************//** diff --git a/storage/innodb_plugin/include/log0recv.h b/storage/innodb_plugin/include/log0recv.h index 8468c213bdb..6de735be945 100644 --- a/storage/innodb_plugin/include/log0recv.h +++ b/storage/innodb_plugin/include/log0recv.h @@ -433,6 +433,11 @@ are allowed yet: the variable name is misleading. */ extern ibool recv_no_ibuf_operations; /** TRUE when recv_init_crash_recovery() has been called. */ extern ibool recv_needed_recovery; +#ifdef UNIV_DEBUG +/** TRUE if writing to the redo log (mtr_commit) is forbidden. +Protected by log_sys->mutex. */ +extern ibool recv_no_log_write; +#endif /* UNIV_DEBUG */ /** TRUE if buf_page_is_corrupted() should check if the log sequence number (FIL_PAGE_LSN) is in the future. Initially FALSE, and set by diff --git a/storage/innodb_plugin/include/mtr0mtr.h b/storage/innodb_plugin/include/mtr0mtr.h index 69a2c03f4cb..bc3f1951be9 100644 --- a/storage/innodb_plugin/include/mtr0mtr.h +++ b/storage/innodb_plugin/include/mtr0mtr.h @@ -106,6 +106,9 @@ For 1 - 8 bytes, the flag value must give the length also! @{ */ #define MLOG_IBUF_BITMAP_INIT ((byte)27) /*!< initialize an ibuf bitmap page */ /*#define MLOG_FULL_PAGE ((byte)28) full contents of a page */ +#ifdef UNIV_LOG_LSN_DEBUG +# define MLOG_LSN ((byte)28) /* current LSN */ +#endif #define MLOG_INIT_FILE_PAGE ((byte)29) /*!< this means that a file page is taken into use and the prior @@ -118,7 +121,7 @@ For 1 - 8 bytes, the flag value must give the length also! @{ */ #define MLOG_WRITE_STRING ((byte)30) /*!< write a string to a page */ #define MLOG_MULTI_REC_END ((byte)31) /*!< if a single mtr writes - log records for several pages, + several log records, this log record ends the sequence of these records */ #define MLOG_DUMMY_RECORD ((byte)32) /*!< dummy log record used to diff --git a/storage/innodb_plugin/include/os0file.h b/storage/innodb_plugin/include/os0file.h index d8d2f0e5d9e..8535ef092c3 100644 --- a/storage/innodb_plugin/include/os0file.h +++ b/storage/innodb_plugin/include/os0file.h @@ -157,6 +157,7 @@ log. */ to become available again */ #define OS_FILE_SHARING_VIOLATION 76 #define OS_FILE_ERROR_NOT_SPECIFIED 77 +#define OS_FILE_INSUFFICIENT_RESOURCE 78 /* @} */ /** Types for aio operations @{ */ diff --git a/storage/innodb_plugin/include/os0sync.h b/storage/innodb_plugin/include/os0sync.h index 0e0b32e7036..0c22162b900 100644 --- a/storage/innodb_plugin/include/os0sync.h +++ b/storage/innodb_plugin/include/os0sync.h @@ -285,44 +285,74 @@ os_fast_mutex_free( /**********************************************************//** Atomic compare-and-swap and increment for InnoDB. */ -#ifdef HAVE_GCC_ATOMIC_BUILTINS +#if defined(HAVE_IB_GCC_ATOMIC_BUILTINS) + +#define HAVE_ATOMIC_BUILTINS + /**********************************************************//** Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ + # define os_compare_and_swap(ptr, old_val, new_val) \ __sync_bool_compare_and_swap(ptr, old_val, new_val) + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) + # define os_compare_and_swap_lint(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) -# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ + +# ifdef HAVE_IB_ATOMIC_PTHREAD_T_GCC +# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ os_compare_and_swap(ptr, old_val, new_val) +# define INNODB_RW_LOCKS_USE_ATOMICS +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes and rw_locks use GCC atomic builtins" +# else /* HAVE_IB_ATOMIC_PTHREAD_T_GCC */ +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes use GCC atomic builtins, rw_locks do not" +# endif /* HAVE_IB_ATOMIC_PTHREAD_T_GCC */ + /**********************************************************//** Returns the resulting value, ptr is pointer to target, amount is the amount of increment. */ + # define os_atomic_increment(ptr, amount) \ __sync_add_and_fetch(ptr, amount) + # define os_atomic_increment_lint(ptr, amount) \ os_atomic_increment(ptr, amount) + # define os_atomic_increment_ulint(ptr, amount) \ os_atomic_increment(ptr, amount) + /**********************************************************//** Returns the old value of *ptr, atomically sets *ptr to new_val */ + # define os_atomic_test_and_set_byte(ptr, new_val) \ __sync_lock_test_and_set(ptr, new_val) + +#elif defined(HAVE_IB_SOLARIS_ATOMICS) + +#define HAVE_ATOMIC_BUILTINS + /* If not compiling with GCC or GCC doesn't support the atomic intrinsics and running on Solaris >= 10 use Solaris atomics */ -#elif defined(HAVE_SOLARIS_ATOMICS) + #include <atomic.h> + /**********************************************************//** Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ (atomic_cas_ulong(ptr, old_val, new_val) == old_val) + # define os_compare_and_swap_lint(ptr, old_val, new_val) \ ((lint)atomic_cas_ulong((ulong_t*) ptr, old_val, new_val) == old_val) -# ifdef INNODB_RW_LOCKS_USE_ATOMICS -# if SIZEOF_PTHREAD_T == 4 + +# ifdef HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS +# if SIZEOF_PTHREAD_T == 4 # define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ ((pthread_t)atomic_cas_32(ptr, old_val, new_val) == old_val) # elif SIZEOF_PTHREAD_T == 8 @@ -331,21 +361,35 @@ compare to, new_val is the value to swap in. */ # else # error "SIZEOF_PTHREAD_T != 4 or 8" # endif /* SIZEOF_PTHREAD_T CHECK */ -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ +# define INNODB_RW_LOCKS_USE_ATOMICS +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes and rw_locks use Solaris atomic functions" +# else /* HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS */ +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes use Solaris atomic functions, rw_locks do not" +# endif /* HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS */ /**********************************************************//** Returns the resulting value, ptr is pointer to target, amount is the amount of increment. */ + # define os_atomic_increment_lint(ptr, amount) \ atomic_add_long_nv((ulong_t*) ptr, amount) + # define os_atomic_increment_ulint(ptr, amount) \ atomic_add_long_nv(ptr, amount) + /**********************************************************//** Returns the old value of *ptr, atomically sets *ptr to new_val */ + # define os_atomic_test_and_set_byte(ptr, new_val) \ atomic_swap_uchar(ptr, new_val) -/* On Windows, use Windows atomics / interlocked */ + #elif defined(HAVE_WINDOWS_ATOMICS) + +#define HAVE_ATOMIC_BUILTINS + +/* On Windows, use Windows atomics / interlocked */ # ifdef _WIN64 # define win_cmp_and_xchg InterlockedCompareExchange64 # define win_xchg_and_add InterlockedExchangeAdd64 @@ -353,31 +397,46 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */ # define win_cmp_and_xchg InterlockedCompareExchange # define win_xchg_and_add InterlockedExchangeAdd # endif + /**********************************************************//** Returns true if swapped, ptr is pointer to target, old_val is value to compare to, new_val is the value to swap in. */ + # define os_compare_and_swap_ulint(ptr, old_val, new_val) \ (win_cmp_and_xchg(ptr, new_val, old_val) == old_val) + # define os_compare_and_swap_lint(ptr, old_val, new_val) \ (win_cmp_and_xchg(ptr, new_val, old_val) == old_val) -# ifdef INNODB_RW_LOCKS_USE_ATOMICS -# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ + +/* windows thread objects can always be passed to windows atomic functions */ +# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \ (InterlockedCompareExchange(ptr, new_val, old_val) == old_val) -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ +# define INNODB_RW_LOCKS_USE_ATOMICS +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes and rw_locks use Windows interlocked functions" + /**********************************************************//** Returns the resulting value, ptr is pointer to target, amount is the amount of increment. */ + # define os_atomic_increment_lint(ptr, amount) \ (win_xchg_and_add(ptr, amount) + amount) + # define os_atomic_increment_ulint(ptr, amount) \ ((ulint) (win_xchg_and_add(ptr, amount) + amount)) + /**********************************************************//** Returns the old value of *ptr, atomically sets *ptr to new_val. InterlockedExchange() operates on LONG, and the LONG will be clobbered */ + # define os_atomic_test_and_set_byte(ptr, new_val) \ ((byte) InterlockedExchange(ptr, new_val)) -#endif /* HAVE_GCC_ATOMIC_BUILTINS */ + +#else +# define IB_ATOMICS_STARTUP_MSG \ + "Mutexes and rw_locks use InnoDB's own implementation" +#endif #ifndef UNIV_NONINL #include "os0sync.ic" diff --git a/storage/innodb_plugin/include/page0page.h b/storage/innodb_plugin/include/page0page.h index a4fe069d022..3899499fb6a 100644 --- a/storage/innodb_plugin/include/page0page.h +++ b/storage/innodb_plugin/include/page0page.h @@ -76,8 +76,11 @@ typedef byte page_header_t; header which are set in a page create */ /*----*/ #define PAGE_LEVEL 26 /* level of the node in an index tree; the - leaf level is the level 0 */ -#define PAGE_INDEX_ID 28 /* index id where the page belongs */ + leaf level is the level 0. This field should + not be written to after page creation. */ +#define PAGE_INDEX_ID 28 /* index id where the page belongs. + This field should not be written to after + page creation. */ #define PAGE_BTR_SEG_LEAF 36 /* file segment header for the leaf pages in a B-tree: defined only on the root page of a B-tree, but not in the root of an ibuf tree */ diff --git a/storage/innodb_plugin/include/page0page.ic b/storage/innodb_plugin/include/page0page.ic index 318ec1cc1f2..8f794410f20 100644 --- a/storage/innodb_plugin/include/page0page.ic +++ b/storage/innodb_plugin/include/page0page.ic @@ -907,7 +907,7 @@ page_get_data_size( /************************************************************//** Allocates a block of memory from the free list of an index page. */ -UNIV_INTERN +UNIV_INLINE void page_mem_alloc_free( /*================*/ diff --git a/storage/innodb_plugin/include/page0zip.h b/storage/innodb_plugin/include/page0zip.h index 9aaa066306b..574809e5227 100644 --- a/storage/innodb_plugin/include/page0zip.h +++ b/storage/innodb_plugin/include/page0zip.h @@ -127,8 +127,12 @@ page_zip_decompress( /*================*/ page_zip_des_t* page_zip,/*!< in: data, ssize; out: m_start, m_end, m_nonempty, n_blobs */ - page_t* page) /*!< out: uncompressed page, may be trashed */ - __attribute__((nonnull)); + page_t* page, /*!< out: uncompressed page, may be trashed */ + ibool all) /*!< in: TRUE=decompress the whole page; + FALSE=verify but do not copy some + page header fields that should not change + after page creation */ + __attribute__((nonnull(1,2))); #ifdef UNIV_DEBUG /**********************************************************************//** @@ -385,8 +389,8 @@ IMPORTANT: if page_zip_reorganize() is invoked on a leaf page of a non-clustered index, the caller must update the insert buffer free bits in the same mini-transaction in such a way that the modification will be redo-logged. -@return TRUE on success, FALSE on failure; page and page_zip will be -left intact on failure. */ +@return TRUE on success, FALSE on failure; page_zip will be left +intact on failure, but page will be overwritten. */ UNIV_INTERN ibool page_zip_reorganize( diff --git a/storage/innodb_plugin/include/rem0cmp.h b/storage/innodb_plugin/include/rem0cmp.h index d30d9f86abe..072f74267ea 100644 --- a/storage/innodb_plugin/include/rem0cmp.h +++ b/storage/innodb_plugin/include/rem0cmp.h @@ -89,7 +89,7 @@ cmp_dfield_dfield( /*************************************************************//** This function is used to compare a data tuple to a physical record. Only dtuple->n_fields_cmp first fields are taken into account for -the the data tuple! If we denote by n = n_fields_cmp, then rec must +the data tuple! If we denote by n = n_fields_cmp, then rec must have either m >= n fields, or it must differ from dtuple in some of the m fields rec has. If rec has an externally stored field we do not compare it but return with value 0 if such a comparison should be diff --git a/storage/innodb_plugin/include/rem0rec.ic b/storage/innodb_plugin/include/rem0rec.ic index 9fe736f9b0b..8e5bd9a7fcd 100644 --- a/storage/innodb_plugin/include/rem0rec.ic +++ b/storage/innodb_plugin/include/rem0rec.ic @@ -65,7 +65,7 @@ most significant bytes and bits are written below less significant. - offset_of_this_record) mod 64Ki, where mod is the modulo as a non-negative number; - we can calculate the the offset of the next + we can calculate the offset of the next record with the formula: relative_offset + offset_of_this_record mod UNIV_PAGE_SIZE diff --git a/storage/innodb_plugin/include/row0ins.h b/storage/innodb_plugin/include/row0ins.h index 530622e6225..9f93565ddb7 100644 --- a/storage/innodb_plugin/include/row0ins.h +++ b/storage/innodb_plugin/include/row0ins.h @@ -45,7 +45,7 @@ row_ins_check_foreign_constraint( /*=============================*/ ibool check_ref,/*!< in: TRUE If we want to check that the referenced table is ok, FALSE if we - want to to check the foreign key table */ + want to check the foreign key table */ dict_foreign_t* foreign,/*!< in: foreign constraint; NOTE that the tables mentioned in it must be in the dictionary cache if they exist at all */ diff --git a/storage/innodb_plugin/include/row0mysql.h b/storage/innodb_plugin/include/row0mysql.h index 97028622505..b05241f00f8 100644 --- a/storage/innodb_plugin/include/row0mysql.h +++ b/storage/innodb_plugin/include/row0mysql.h @@ -177,7 +177,9 @@ row_update_prebuilt_trx( in MySQL handle */ trx_t* trx); /*!< in: transaction handle */ /*********************************************************************//** -Unlocks AUTO_INC type locks that were possibly reserved by a trx. */ +Unlocks AUTO_INC type locks that were possibly reserved by a trx. This +function should be called at the the end of an SQL statement, by the +connection thread that owns the transaction (trx->mysql_thd). */ UNIV_INTERN void row_unlock_table_autoinc_for_mysql( @@ -754,8 +756,6 @@ struct row_prebuilt_struct { store it here so that we can return it to MySQL */ /*----------------------*/ - UT_LIST_NODE_T(row_prebuilt_t) prebuilts; - /*!< list node of table->prebuilts */ ulint magic_n2; /*!< this should be the same as magic_n */ }; diff --git a/storage/innodb_plugin/include/srv0srv.h b/storage/innodb_plugin/include/srv0srv.h index 499bccfe2b8..23472bd100e 100644 --- a/storage/innodb_plugin/include/srv0srv.h +++ b/storage/innodb_plugin/include/srv0srv.h @@ -315,10 +315,6 @@ extern ulint srv_buf_pool_flushed; /** Number of buffer pool reads that led to the reading of a disk page */ extern ulint srv_buf_pool_reads; -/** Number of sequential read-aheads */ -extern ulint srv_read_ahead_seq; -/** Number of random read-aheads */ -extern ulint srv_read_ahead_rnd; /** Status variables to be passed to MySQL */ typedef struct export_var_struct export_struc; @@ -605,13 +601,13 @@ struct export_var_struct{ #ifdef UNIV_DEBUG ulint innodb_buffer_pool_pages_latched; /*!< Latched pages */ #endif /* UNIV_DEBUG */ - ulint innodb_buffer_pool_read_requests; /*!< buf_pool->n_page_gets */ + ulint innodb_buffer_pool_read_requests; /*!< buf_pool->stat.n_page_gets */ ulint innodb_buffer_pool_reads; /*!< srv_buf_pool_reads */ ulint innodb_buffer_pool_wait_free; /*!< srv_buf_pool_wait_free */ ulint innodb_buffer_pool_pages_flushed; /*!< srv_buf_pool_flushed */ ulint innodb_buffer_pool_write_requests;/*!< srv_buf_pool_write_requests */ - ulint innodb_buffer_pool_read_ahead_seq;/*!< srv_read_ahead_seq */ - ulint innodb_buffer_pool_read_ahead_rnd;/*!< srv_read_ahead_rnd */ + ulint innodb_buffer_pool_read_ahead; /*!< srv_read_ahead */ + ulint innodb_buffer_pool_read_ahead_evicted;/*!< srv_read_ahead evicted*/ ulint innodb_dblwr_pages_written; /*!< srv_dblwr_pages_written */ ulint innodb_dblwr_writes; /*!< srv_dblwr_writes */ ibool innodb_have_atomic_builtins; /*!< HAVE_ATOMIC_BUILTINS */ @@ -623,9 +619,9 @@ struct export_var_struct{ ulint innodb_os_log_pending_writes; /*!< srv_os_log_pending_writes */ ulint innodb_os_log_pending_fsyncs; /*!< fil_n_pending_log_flushes */ ulint innodb_page_size; /*!< UNIV_PAGE_SIZE */ - ulint innodb_pages_created; /*!< buf_pool->n_pages_created */ - ulint innodb_pages_read; /*!< buf_pool->n_pages_read */ - ulint innodb_pages_written; /*!< buf_pool->n_pages_written */ + ulint innodb_pages_created; /*!< buf_pool->stat.n_pages_created */ + ulint innodb_pages_read; /*!< buf_pool->stat.n_pages_read */ + ulint innodb_pages_written; /*!< buf_pool->stat.n_pages_written */ ulint innodb_row_lock_waits; /*!< srv_n_lock_wait_count */ ulint innodb_row_lock_current_waits; /*!< srv_n_lock_wait_current_count */ ib_int64_t innodb_row_lock_time; /*!< srv_n_lock_wait_time diff --git a/storage/innodb_plugin/include/trx0rec.h b/storage/innodb_plugin/include/trx0rec.h index 0ae82c33afe..a6e56e963c6 100644 --- a/storage/innodb_plugin/include/trx0rec.h +++ b/storage/innodb_plugin/include/trx0rec.h @@ -44,8 +44,8 @@ UNIV_INLINE trx_undo_rec_t* trx_undo_rec_copy( /*==============*/ - trx_undo_rec_t* undo_rec, /*!< in: undo log record */ - mem_heap_t* heap); /*!< in: heap where copied */ + const trx_undo_rec_t* undo_rec, /*!< in: undo log record */ + mem_heap_t* heap); /*!< in: heap where copied */ /**********************************************************************//** Reads the undo log record type. @return record type */ diff --git a/storage/innodb_plugin/include/trx0rec.ic b/storage/innodb_plugin/include/trx0rec.ic index 037b5d4f6cf..e7e41d6d9f6 100644 --- a/storage/innodb_plugin/include/trx0rec.ic +++ b/storage/innodb_plugin/include/trx0rec.ic @@ -100,8 +100,8 @@ UNIV_INLINE trx_undo_rec_t* trx_undo_rec_copy( /*==============*/ - trx_undo_rec_t* undo_rec, /*!< in: undo log record */ - mem_heap_t* heap) /*!< in: heap where copied */ + const trx_undo_rec_t* undo_rec, /*!< in: undo log record */ + mem_heap_t* heap) /*!< in: heap where copied */ { ulint len; diff --git a/storage/innodb_plugin/include/trx0roll.h b/storage/innodb_plugin/include/trx0roll.h index ddca9e9e4ef..1dee5655c8c 100644 --- a/storage/innodb_plugin/include/trx0roll.h +++ b/storage/innodb_plugin/include/trx0roll.h @@ -133,6 +133,17 @@ trx_rollback( Rollback or clean up any incomplete transactions which were encountered in crash recovery. If the transaction already was committed, then we clean up a possible insert undo log. If the +transaction was not yet committed, then we roll it back. */ +UNIV_INTERN +void +trx_rollback_or_clean_recovered( +/*============================*/ + ibool all); /*!< in: FALSE=roll back dictionary transactions; + TRUE=roll back all non-PREPARED transactions */ +/*******************************************************************//** +Rollback or clean up any incomplete transactions which were +encountered in crash recovery. If the transaction already was +committed, then we clean up a possible insert undo log. If the transaction was not yet committed, then we roll it back. Note: this is done in a background thread. @return a dummy parameter */ @@ -208,9 +219,9 @@ int trx_general_rollback_for_mysql( /*===========================*/ trx_t* trx, /*!< in: transaction handle */ - ibool partial,/*!< in: TRUE if partial rollback requested */ trx_savept_t* savept);/*!< in: pointer to savepoint undo number, if - partial rollback requested */ + partial rollback requested, or NULL for + complete rollback */ /*******************************************************************//** Rolls back a transaction back to a named savepoint. Modifications after the savepoint are undone but InnoDB does NOT release the corresponding locks diff --git a/storage/innodb_plugin/include/trx0sys.ic b/storage/innodb_plugin/include/trx0sys.ic index 1c7c732751b..820d31d0692 100644 --- a/storage/innodb_plugin/include/trx0sys.ic +++ b/storage/innodb_plugin/include/trx0sys.ic @@ -34,11 +34,11 @@ typedef byte trx_sysf_rseg_t; /* Rollback segment specification slot offsets */ /*-------------------------------------------------------------*/ -#define TRX_SYS_RSEG_SPACE 0 /* space where the the segment +#define TRX_SYS_RSEG_SPACE 0 /* space where the segment header is placed; starting with MySQL/InnoDB 5.1.7, this is UNIV_UNDEFINED if the slot is unused */ -#define TRX_SYS_RSEG_PAGE_NO 4 /* page number where the the segment +#define TRX_SYS_RSEG_PAGE_NO 4 /* page number where the segment header is placed; this is FIL_NULL if the slot is unused */ /*-------------------------------------------------------------*/ diff --git a/storage/innodb_plugin/include/trx0trx.h b/storage/innodb_plugin/include/trx0trx.h index 681feeaec94..d2a59740c93 100644 --- a/storage/innodb_plugin/include/trx0trx.h +++ b/storage/innodb_plugin/include/trx0trx.h @@ -179,7 +179,7 @@ trx_commit_off_kernel( /****************************************************************//** Cleans up a transaction at database startup. The cleanup is needed if the transaction already got to the middle of a commit when the database -crashed, andf we cannot roll it back. */ +crashed, and we cannot roll it back. */ UNIV_INTERN void trx_cleanup_at_db_startup( @@ -360,7 +360,7 @@ enum trx_dict_op { operation modes in crash recovery. */ TRX_DICT_OP_TABLE = 1, /** The transaction is creating or dropping an index in an - existing table. In crash recovery, the the data dictionary + existing table. In crash recovery, the data dictionary must be locked, but the table must not be dropped. */ TRX_DICT_OP_INDEX = 2 }; diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index 023a6c9cd89..5d0361658af 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -46,11 +46,11 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 1 #define INNODB_VERSION_MINOR 0 -#define INNODB_VERSION_BUGFIX 4 +#define INNODB_VERSION_BUGFIX 5 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; -calculated in in make_version_string() in sql/sql_show.cc like this: +calculated in make_version_string() in sql/sql_show.cc like this: "version >> 8" . "version & 0xff" because the version is shown with only one dot, we skip the last component, i.e. we show M.N.P as M.N */ @@ -78,17 +78,25 @@ the virtual method table (vtable) in GCC 3. */ # define ha_innobase ha_innodb #endif /* MYSQL_DYNAMIC_PLUGIN */ +/* if any of the following macros is defined at this point this means +that the code from the "right" plug.in was executed and we do not +need to include ut0auxconf.h which would either define the same macros +or will be empty */ +#if !defined(HAVE_IB_GCC_ATOMIC_BUILTINS) \ + && !defined(HAVE_IB_ATOMIC_PTHREAD_T_GCC) \ + && !defined(HAVE_IB_SOLARIS_ATOMICS) \ + && !defined(HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS) \ + && !defined(SIZEOF_PTHREAD_T) \ + && !defined(HAVE_IB_PAUSE_INSTRUCTION) +# include "ut0auxconf.h" +#endif + #if (defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)) && !defined(MYSQL_SERVER) && !defined(__WIN__) # undef __WIN__ # define __WIN__ # include <windows.h> -# if defined(HAVE_WINDOWS_ATOMICS) -/* If atomics are defined we use them in InnoDB mutex implementation */ -# define HAVE_ATOMIC_BUILTINS -# endif /* HAVE_WINDOWS_ATOMICS */ - # ifdef _NT_ # define __NT__ # endif @@ -111,45 +119,17 @@ if we are compiling on Windows. */ # include <sys/mman.h> /* mmap() for os0proc.c */ # endif -# undef PACKAGE -# undef VERSION - /* Include the header file generated by GNU autoconf */ # ifndef __WIN__ -#ifndef UNIV_HOTBACKUP -# include "config.h" -#endif /* UNIV_HOTBACKUP */ +# ifndef UNIV_HOTBACKUP +# include "config.h" +# endif /* UNIV_HOTBACKUP */ # endif # ifdef HAVE_SCHED_H # include <sched.h> # endif -# if defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_SOLARIS_ATOMICS) \ - || defined(HAVE_WINDOWS_ATOMICS) -/* If atomics are defined we use them in InnoDB mutex implementation */ -# define HAVE_ATOMIC_BUILTINS -# endif /* (HAVE_GCC_ATOMIC_BUILTINS) || (HAVE_SOLARIS_ATOMICS) - || (HAVE_WINDOWS_ATOMICS) */ - -/* For InnoDB rw_locks to work with atomics we need the thread_id -to be no more than machine word wide. The following enables using -atomics for InnoDB rw_locks where these conditions are met. */ -#ifdef HAVE_ATOMIC_BUILTINS -/* if HAVE_ATOMIC_PTHREAD_T is defined at this point that means that -the code from plug.in has defined it and we do not need to include -ut0auxconf.h which would either define HAVE_ATOMIC_PTHREAD_T or will -be empty */ -# ifndef HAVE_ATOMIC_PTHREAD_T -# include "ut0auxconf.h" -# endif /* HAVE_ATOMIC_PTHREAD_T */ -/* now HAVE_ATOMIC_PTHREAD_T is eventually defined either by plug.in or -from Makefile.in->ut0auxconf.h */ -# ifdef HAVE_ATOMIC_PTHREAD_T -# define INNODB_RW_LOCKS_USE_ATOMICS -# endif /* HAVE_ATOMIC_PTHREAD_T */ -#endif /* HAVE_ATOMIC_BUILTINS */ - /* We only try to do explicit inlining of functions with gcc and Sun Studio */ @@ -196,12 +176,18 @@ command. Not tested on Windows. */ debugging without UNIV_DEBUG */ #define UNIV_DEBUG /* Enable ut_ad() assertions and disable UNIV_INLINE */ +#define UNIV_DEBUG_LOCK_VALIDATE /* Enable + ut_ad(lock_rec_validate_page()) + assertions. */ #define UNIV_DEBUG_FILE_ACCESSES /* Debug .ibd file access (field file_page_was_freed in buf_page_t) */ #define UNIV_LRU_DEBUG /* debug the buffer pool LRU */ #define UNIV_HASH_DEBUG /* debug HASH_ macros */ #define UNIV_LIST_DEBUG /* debug UT_LIST_ macros */ +#define UNIV_LOG_LSN_DEBUG /* write LSN to the redo log; +this will break redo log file compatibility, but it may be useful when +debugging redo log application problems. */ #define UNIV_MEM_DEBUG /* detect memory leaks etc */ #define UNIV_IBUF_DEBUG /* debug the insert buffer */ #define UNIV_IBUF_COUNT_DEBUG /* debug the insert buffer; @@ -251,7 +237,7 @@ by one. */ /* Linkage specifier for non-static InnoDB symbols (variables and functions) that are only referenced from within InnoDB, not from MySQL */ -#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(UNIV_HOTBACKUP) +#if defined(__GNUC__) && (__GNUC__ >= 4) || defined(__INTEL_COMPILER) # define UNIV_INTERN __attribute__((visibility ("hidden"))) #else # define UNIV_INTERN @@ -409,7 +395,8 @@ it is read. */ it is read or written. */ # define UNIV_PREFETCH_RW(addr) __builtin_prefetch(addr, 1, 3) /* Sun Studio includes sun_prefetch.h as of version 5.9 */ -#elif (defined(__SUNPRO_C) && __SUNPRO_C >= 0x590) || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x590) +#elif (defined(__SUNPRO_C) && __SUNPRO_C >= 0x590) \ + || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x590) # include <sun_prefetch.h> #if __SUNPRO_C >= 0x550 # undef UNIV_INTERN diff --git a/storage/innodb_plugin/include/ut0auxconf.h b/storage/innodb_plugin/include/ut0auxconf.h index 88fb26f1863..16bcc308392 100644 --- a/storage/innodb_plugin/include/ut0auxconf.h +++ b/storage/innodb_plugin/include/ut0auxconf.h @@ -1,14 +1,14 @@ /* Do not remove this file even though it is empty. This file is included in univ.i and will cause compilation failure if not present. -A custom check has been added in the generated +A custom checks have been added in the generated storage/innobase/Makefile.in that is shipped with the InnoDB Plugin -source archive. This check tries to compile a test program and if -successful then adds "#define HAVE_ATOMIC_PTHREAD_T" to this file. -This is a hack that has been developed in order to check for pthread_t -atomicity without the need to regenerate the ./configure script that is +source archive. These checks eventually define some macros and put +them in this file. +This is a hack that has been developed in order to deploy new compile +time checks without the need to regenerate the ./configure script that is distributed in the MySQL 5.1 official source archives. If by any chance Makefile.in and ./configure are regenerated and thus -the hack from Makefile.in wiped away then the "real" check from plug.in +the hack from Makefile.in wiped away then the "real" checks from plug.in will take over. */ diff --git a/storage/innodb_plugin/include/ut0byte.h b/storage/innodb_plugin/include/ut0byte.h index a2687e62f08..f55e2888c60 100644 --- a/storage/innodb_plugin/include/ut0byte.h +++ b/storage/innodb_plugin/include/ut0byte.h @@ -219,8 +219,8 @@ UNIV_INLINE void* ut_align( /*=====*/ - void* ptr, /*!< in: pointer */ - ulint align_no); /*!< in: align by this number */ + const void* ptr, /*!< in: pointer */ + ulint align_no); /*!< in: align by this number */ /*********************************************************//** The following function rounds down a pointer to the nearest aligned address. diff --git a/storage/innodb_plugin/include/ut0byte.ic b/storage/innodb_plugin/include/ut0byte.ic index e3beed65138..3dd51890cb4 100644 --- a/storage/innodb_plugin/include/ut0byte.ic +++ b/storage/innodb_plugin/include/ut0byte.ic @@ -319,8 +319,8 @@ UNIV_INLINE void* ut_align( /*=====*/ - void* ptr, /*!< in: pointer */ - ulint align_no) /*!< in: align by this number */ + const void* ptr, /*!< in: pointer */ + ulint align_no) /*!< in: align by this number */ { ut_ad(align_no > 0); ut_ad(((align_no - 1) & align_no) == 0); diff --git a/storage/innodb_plugin/include/ut0ut.h b/storage/innodb_plugin/include/ut0ut.h index 80094321041..197b8401428 100644 --- a/storage/innodb_plugin/include/ut0ut.h +++ b/storage/innodb_plugin/include/ut0ut.h @@ -34,6 +34,11 @@ Created 1/20/1994 Heikki Tuuri #define ut0ut_h #include "univ.i" + +#ifndef UNIV_HOTBACKUP +# include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ +#endif /* UNIV_HOTBACKUP */ + #include <time.h> #ifndef MYSQL_SERVER #include <ctype.h> @@ -47,7 +52,8 @@ Created 1/20/1994 Heikki Tuuri /** Time stamp */ typedef time_t ib_time_t; -#if defined(IB_HAVE_PAUSE_INSTRUCTION) +#ifndef UNIV_HOTBACKUP +#if defined(HAVE_IB_PAUSE_INSTRUCTION) # ifdef WIN32 /* In the Win32 API, the x86 PAUSE instruction is executed by calling the YieldProcessor macro defined in WinNT.h. It is a CPU architecture- @@ -84,6 +90,7 @@ do { \ os_thread_sleep(2000 /* 2 ms */); \ } \ } while (0) +#endif /* !UNIV_HOTBACKUP */ /********************************************************//** Gets the high 32 bits in a ulint. That is makes a shift >> 32, @@ -216,6 +223,7 @@ UNIV_INTERN ib_time_t ut_time(void); /*=========*/ +#ifndef UNIV_HOTBACKUP /**********************************************************//** Returns system time. Upon successful completion, the value 0 is returned; otherwise the @@ -239,6 +247,16 @@ ullint ut_time_us( /*=======*/ ullint* tloc); /*!< out: us since epoch, if non-NULL */ +/**********************************************************//** +Returns the number of milliseconds since some epoch. The +value may wrap around. It should only be used for heuristic +purposes. +@return ms since epoch */ +UNIV_INTERN +ulint +ut_time_ms(void); +/*============*/ +#endif /* !UNIV_HOTBACKUP */ /**********************************************************//** Returns the difference of two times in seconds. diff --git a/storage/innodb_plugin/lock/lock0lock.c b/storage/innodb_plugin/lock/lock0lock.c index fcd8d268331..67b2eac7219 100644 --- a/storage/innodb_plugin/lock/lock0lock.c +++ b/storage/innodb_plugin/lock/lock0lock.c @@ -214,7 +214,7 @@ a waiting s-lock request on the next record? If this s-lock was placed by a read cursor moving in the ascending order in the index, we cannot do the insert immediately, because when we finally commit our transaction, the read cursor should see also the new inserted record. So we should -move the read cursor backward from the the next record for it to pass over +move the read cursor backward from the next record for it to pass over the new inserted record. This move backward may be too cumbersome to implement. If we in this situation just enqueue a second x-lock request for our transaction on the next record, then the deadlock mechanism @@ -360,10 +360,9 @@ ibool lock_rec_validate_page( /*===================*/ ulint space, /*!< in: space id */ + ulint zip_size,/*!< in: compressed page size in bytes + or 0 for uncompressed pages */ ulint page_no);/*!< in: page number */ - -/* Define the following in order to enable lock_rec_validate_page() checks. */ -# undef UNIV_DEBUG_LOCK_VALIDATE #endif /* UNIV_DEBUG */ /* The lock system */ @@ -2622,6 +2621,7 @@ lock_move_reorganize_page( #ifdef UNIV_DEBUG_LOCK_VALIDATE ut_ad(lock_rec_validate_page(buf_block_get_space(block), + buf_block_get_zip_size(block), buf_block_get_page_no(block))); #endif } @@ -2711,8 +2711,10 @@ lock_move_rec_list_end( #ifdef UNIV_DEBUG_LOCK_VALIDATE ut_ad(lock_rec_validate_page(buf_block_get_space(block), + buf_block_get_zip_size(block), buf_block_get_page_no(block))); ut_ad(lock_rec_validate_page(buf_block_get_space(new_block), + buf_block_get_zip_size(block), buf_block_get_page_no(new_block))); #endif } @@ -2822,6 +2824,7 @@ lock_move_rec_list_start( #ifdef UNIV_DEBUG_LOCK_VALIDATE ut_ad(lock_rec_validate_page(buf_block_get_space(block), + buf_block_get_zip_size(block), buf_block_get_page_no(block))); #endif } @@ -3574,7 +3577,8 @@ lock_table_remove_low( and lock_grant()). Therefore it can be empty and we need to check for that. */ - if (!ib_vector_is_empty(trx->autoinc_locks)) { + if (!lock_get_wait(lock) + && !ib_vector_is_empty(trx->autoinc_locks)) { lock_t* autoinc_lock; autoinc_lock = ib_vector_pop(trx->autoinc_locks); @@ -3647,8 +3651,10 @@ lock_table_enqueue_waiting( if (lock_deadlock_occurs(lock, trx)) { - lock_reset_lock_and_trx_wait(lock); + /* The order here is important, we don't want to + lose the state of the lock before calling remove. */ lock_table_remove_low(lock); + lock_reset_lock_and_trx_wait(lock); return(DB_DEADLOCK); } @@ -4627,6 +4633,10 @@ lock_rec_queue_validate( next function call: we have to release lock table mutex to obey the latching order */ + /* If this thread is holding the file space latch + (fil_space_t::latch), the following check WILL break + latching order and may cause a deadlock of threads. */ + impl_trx = lock_sec_rec_some_has_impl_off_kernel( rec, index, offsets); @@ -4684,6 +4694,8 @@ ibool lock_rec_validate_page( /*===================*/ ulint space, /*!< in: space id */ + ulint zip_size,/*!< in: compressed page size in bytes + or 0 for uncompressed pages */ ulint page_no)/*!< in: page number */ { dict_index_t* index; @@ -4694,7 +4706,6 @@ lock_rec_validate_page( ulint nth_lock = 0; ulint nth_bit = 0; ulint i; - ulint zip_size; mtr_t mtr; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; @@ -4705,7 +4716,6 @@ lock_rec_validate_page( mtr_start(&mtr); - zip_size = fil_space_get_zip_size(space); ut_ad(zip_size != ULINT_UNDEFINED); block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, &mtr); buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK); @@ -4750,6 +4760,11 @@ loop: lock_mutex_exit_kernel(); + /* If this thread is holding the file space + latch (fil_space_t::latch), the following + check WILL break the latching order and may + cause a deadlock of threads. */ + lock_rec_queue_validate(block, rec, index, offsets); lock_mutex_enter_kernel(); @@ -4840,7 +4855,9 @@ lock_validate(void) lock_mutex_exit_kernel(); - lock_rec_validate_page(space, page_no); + lock_rec_validate_page(space, + fil_space_get_zip_size(space), + page_no); lock_mutex_enter_kernel(); @@ -5364,6 +5381,20 @@ lock_release_autoinc_last_lock( } /*******************************************************************//** +Check if a transaction holds any autoinc locks. +@return TRUE if the transaction holds any AUTOINC locks. */ +UNIV_INTERN +ibool +lock_trx_holds_autoinc_locks( +/*=========================*/ + const trx_t* trx) /*!< in: transaction */ +{ + ut_a(trx->autoinc_locks != NULL); + + return(!ib_vector_is_empty(trx->autoinc_locks)); +} + +/*******************************************************************//** Release all the transaction's autoinc locks. */ UNIV_INTERN void diff --git a/storage/innodb_plugin/log/log0log.c b/storage/innodb_plugin/log/log0log.c index 24c828cdf5f..a23dd20772a 100644 --- a/storage/innodb_plugin/log/log0log.c +++ b/storage/innodb_plugin/log/log0log.c @@ -241,6 +241,7 @@ log_reserve_and_open( ut_a(len < log->buf_size / 2); loop: mutex_enter(&(log->mutex)); + ut_ad(!recv_no_log_write); /* Calculate an upper limit for the space the string may take in the log buffer */ @@ -309,6 +310,7 @@ log_write_low( ut_ad(mutex_own(&(log->mutex))); part_loop: + ut_ad(!recv_no_log_write); /* Calculate a part length */ data_len = (log->buf_free % OS_FILE_LOG_BLOCK_SIZE) + str_len; @@ -377,6 +379,7 @@ log_close(void) ib_uint64_t checkpoint_age; ut_ad(mutex_own(&(log->mutex))); + ut_ad(!recv_no_log_write); lsn = log->lsn; @@ -668,8 +671,6 @@ log_calc_max_ages(void) ulint archive_margin; ulint smallest_archive_margin; - ut_ad(!mutex_own(&(log_sys->mutex))); - mutex_enter(&(log_sys->mutex)); group = UT_LIST_GET_FIRST(log_sys->log_groups); @@ -1117,6 +1118,7 @@ log_io_complete( } mutex_enter(&(log_sys->mutex)); + ut_ad(!recv_no_log_write); ut_a(group->n_pending_writes > 0); ut_a(log_sys->n_pending_writes > 0); @@ -1148,6 +1150,7 @@ log_group_file_header_flush( ulint dest_offset; ut_ad(mutex_own(&(log_sys->mutex))); + ut_ad(!recv_no_log_write); ut_a(nth_file < group->n_files); buf = *(group->file_header_bufs + nth_file); @@ -1219,6 +1222,7 @@ log_group_write_buf( ulint i; ut_ad(mutex_own(&(log_sys->mutex))); + ut_ad(!recv_no_log_write); ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0); ut_a(((ulint) start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); @@ -1361,6 +1365,7 @@ loop: #endif mutex_enter(&(log_sys->mutex)); + ut_ad(!recv_no_log_write); if (flush_to_disk && log_sys->flushed_to_disk_lsn >= lsn) { @@ -1974,6 +1979,7 @@ log_checkpoint( mutex_enter(&(log_sys->mutex)); + ut_ad(!recv_no_log_write); oldest_lsn = log_buf_pool_get_oldest_modification(); mutex_exit(&(log_sys->mutex)); @@ -2047,7 +2053,7 @@ log_make_checkpoint_at( later lsn, if IB_ULONGLONG_MAX, makes a checkpoint at the latest lsn */ ibool write_always) /*!< in: the function normally checks if - the the new checkpoint would have a + the new checkpoint would have a greater lsn than the previous one: if not, then no physical write is done; by setting this parameter TRUE, a @@ -2086,6 +2092,7 @@ loop: do_checkpoint = FALSE; mutex_enter(&(log->mutex)); + ut_ad(!recv_no_log_write); if (log->check_flush_or_checkpoint == FALSE) { mutex_exit(&(log->mutex)); @@ -3035,6 +3042,7 @@ loop: #endif /* UNIV_LOG_ARCHIVE */ mutex_enter(&(log_sys->mutex)); + ut_ad(!recv_no_log_write); if (log_sys->check_flush_or_checkpoint) { @@ -3234,6 +3242,7 @@ loop: ut_a(lsn == log_sys->lsn); } +#ifdef UNIV_LOG_DEBUG /******************************************************//** Checks by parsing that the catenated log segment for a single mtr is consistent. */ @@ -3241,7 +3250,7 @@ UNIV_INTERN ibool log_check_log_recs( /*===============*/ - byte* buf, /*!< in: pointer to the start of + const byte* buf, /*!< in: pointer to the start of the log segment in the log_sys->buf log buffer */ ulint len, /*!< in: segment length in bytes */ @@ -3249,8 +3258,8 @@ log_check_log_recs( { ib_uint64_t contiguous_lsn; ib_uint64_t scanned_lsn; - byte* start; - byte* end; + const byte* start; + const byte* end; byte* buf1; byte* scan_buf; @@ -3283,6 +3292,7 @@ log_check_log_recs( return(TRUE); } +#endif /* UNIV_LOG_DEBUG */ /******************************************************//** Peeks the current lsn. diff --git a/storage/innodb_plugin/log/log0recv.c b/storage/innodb_plugin/log/log0recv.c index aea29c78517..81dcc9cd4f8 100644 --- a/storage/innodb_plugin/log/log0recv.c +++ b/storage/innodb_plugin/log/log0recv.c @@ -78,6 +78,11 @@ UNIV_INTERN ibool recv_recovery_from_backup_on = FALSE; #ifndef UNIV_HOTBACKUP /** TRUE when recv_init_crash_recovery() has been called. */ UNIV_INTERN ibool recv_needed_recovery = FALSE; +# ifdef UNIV_DEBUG +/** TRUE if writing to the redo log (mtr_commit) is forbidden. +Protected by log_sys->mutex. */ +UNIV_INTERN ibool recv_no_log_write = FALSE; +# endif /* UNIV_DEBUG */ /** TRUE if buf_page_is_corrupted() should check if the log sequence number (FIL_PAGE_LSN) is in the future. Initially FALSE, and set by @@ -853,6 +858,11 @@ recv_parse_or_apply_log_rec_body( } switch (type) { +#ifdef UNIV_LOG_LSN_DEBUG + case MLOG_LSN: + /* The LSN is checked in recv_parse_log_rec(). */ + break; +#endif /* UNIV_LOG_LSN_DEBUG */ case MLOG_1BYTE: case MLOG_2BYTES: case MLOG_4BYTES: case MLOG_8BYTES: #ifdef UNIV_DEBUG if (page && page_type == FIL_PAGE_TYPE_ALLOCATED @@ -1269,7 +1279,7 @@ recv_add_to_hash_table( sizeof(recv_data_t) + len); *prev_field = recv_data; - ut_memcpy(((byte*)recv_data) + sizeof(recv_data_t), body, len); + memcpy(recv_data + 1, body, len); prev_field = &(recv_data->next); @@ -1327,6 +1337,7 @@ recv_recover_page_func( buf_block_t* block) /*!< in/out: buffer block */ { page_t* page; + page_zip_des_t* page_zip; recv_addr_t* recv_addr; recv_t* recv; byte* buf; @@ -1376,6 +1387,7 @@ recv_recover_page_func( mtr_set_log_mode(&mtr, MTR_LOG_NONE); page = block->frame; + page_zip = buf_block_get_page_zip(block); #ifndef UNIV_HOTBACKUP if (just_read_in) { @@ -1436,13 +1448,19 @@ recv_recover_page_func( if (recv->type == MLOG_INIT_FILE_PAGE) { page_lsn = page_newest_lsn; - mach_write_ull(page + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN_OLD_CHKSUM, 0); - mach_write_ull(page + FIL_PAGE_LSN, 0); + memset(FIL_PAGE_LSN + page, 0, 8); + memset(UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM + + page, 0, 8); + + if (page_zip) { + memset(FIL_PAGE_LSN + page_zip->data, 0, 8); + } } if (recv->start_lsn >= page_lsn) { + ib_uint64_t end_lsn; + if (!modification_to_page) { modification_to_page = TRUE; @@ -1464,11 +1482,17 @@ recv_recover_page_func( recv_parse_or_apply_log_rec_body(recv->type, buf, buf + recv->len, block, &mtr); - mach_write_ull(page + UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN_OLD_CHKSUM, - recv->start_lsn + recv->len); - mach_write_ull(page + FIL_PAGE_LSN, - recv->start_lsn + recv->len); + + end_lsn = recv->start_lsn + recv->len; + mach_write_ull(FIL_PAGE_LSN + page, end_lsn); + mach_write_ull(UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN_OLD_CHKSUM + + page, end_lsn); + + if (page_zip) { + mach_write_ull(FIL_PAGE_LSN + + page_zip->data, end_lsn); + } } if (recv->len > RECV_DATA_BLOCK_SIZE) { @@ -1686,6 +1710,7 @@ loop: /* Flush all the file pages to disk and invalidate them in the buffer pool */ + ut_d(recv_no_log_write = TRUE); mutex_exit(&(recv_sys->mutex)); mutex_exit(&(log_sys->mutex)); @@ -1699,6 +1724,7 @@ loop: mutex_enter(&(log_sys->mutex)); mutex_enter(&(recv_sys->mutex)); + ut_d(recv_no_log_write = FALSE); recv_no_ibuf_operations = FALSE; } @@ -1910,6 +1936,17 @@ recv_parse_log_rec( return(0); } +#ifdef UNIV_LOG_LSN_DEBUG + if (*type == MLOG_LSN) { + ib_uint64_t lsn = (ib_uint64_t) *space << 32 | *page_no; +# ifdef UNIV_LOG_DEBUG + ut_a(lsn == log_sys->old_lsn); +# else /* UNIV_LOG_DEBUG */ + ut_a(lsn == recv_sys->recovered_lsn); +# endif /* UNIV_LOG_DEBUG */ + } +#endif /* UNIV_LOG_LSN_DEBUG */ + /* Check that page_no is sensible */ if (UNIV_UNLIKELY(*page_no > 0x8FFFFFFFUL)) { @@ -2167,6 +2204,12 @@ loop: #endif /* In normal mysqld crash recovery we do not try to replay file operations */ +#ifdef UNIV_LOG_LSN_DEBUG + } else if (type == MLOG_LSN) { + /* Do not add these records to the hash table. + The page number and space id fields are misused + for something else. */ +#endif /* UNIV_LOG_LSN_DEBUG */ } else { recv_add_to_hash_table(type, space, page_no, body, ptr + len, old_lsn, @@ -2198,11 +2241,11 @@ loop: = recv_sys->recovered_offset + total_len; recv_previous_parsed_rec_is_multi = 1; - if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) { #ifdef UNIV_LOG_DEBUG + if ((!store_to_hash) && (type != MLOG_MULTI_REC_END)) { recv_check_incomplete_log_recs(ptr, len); -#endif /* UNIV_LOG_DEBUG */ } +#endif /* UNIV_LOG_DEBUG */ #ifdef UNIV_DEBUG if (log_debug_writes) { @@ -2266,7 +2309,11 @@ loop: break; } - if (store_to_hash) { + if (store_to_hash +#ifdef UNIV_LOG_LSN_DEBUG + && type != MLOG_LSN +#endif /* UNIV_LOG_LSN_DEBUG */ + ) { recv_add_to_hash_table(type, space, page_no, body, ptr + len, old_lsn, @@ -2415,8 +2462,7 @@ recv_scan_log_recs( scanned_lsn = start_lsn; more_data = FALSE; - while (log_block < buf + len && !finished) { - + do { no = log_block_get_hdr_no(log_block); /* fprintf(stderr, "Log block header no %lu\n", no); @@ -2546,10 +2592,11 @@ recv_scan_log_recs( /* Log data for this group ends here */ finished = TRUE; + break; } else { log_block += OS_FILE_LOG_BLOCK_SIZE; } - } + } while (log_block < buf + len && !finished); *group_scanned_lsn = scanned_lsn; @@ -3104,6 +3151,11 @@ recv_recovery_from_checkpoint_finish(void) #ifndef UNIV_LOG_DEBUG recv_sys_free(); #endif + /* Roll back any recovered data dictionary transactions, so + that the data dictionary tables will be free of any locks. + The data dictionary latch should guarantee that there is at + most one data dictionary transaction active at a time. */ + trx_rollback_or_clean_recovered(FALSE); /* Drop partially created indexes. */ row_merge_drop_temp_indexes(); diff --git a/storage/innodb_plugin/mem/mem0mem.c b/storage/innodb_plugin/mem/mem0mem.c index e0dc8716f13..ccb2fd8a7b4 100644 --- a/storage/innodb_plugin/mem/mem0mem.c +++ b/storage/innodb_plugin/mem/mem0mem.c @@ -475,16 +475,18 @@ mem_heap_block_free( len = block->len; block->magic_n = MEM_FREED_BLOCK_MAGIC_N; +#ifndef UNIV_HOTBACKUP + if (!srv_use_sys_malloc) { #ifdef UNIV_MEM_DEBUG - /* In the debug version we set the memory to a random combination - of hex 0xDE and 0xAD. */ + /* In the debug version we set the memory to a random + combination of hex 0xDE and 0xAD. */ - mem_erase_buf((byte*)block, len); + mem_erase_buf((byte*)block, len); #else /* UNIV_MEM_DEBUG */ - UNIV_MEM_ASSERT_AND_FREE(block, len); + UNIV_MEM_ASSERT_AND_FREE(block, len); #endif /* UNIV_MEM_DEBUG */ -#ifndef UNIV_HOTBACKUP + } if (type == MEM_HEAP_DYNAMIC || len < UNIV_PAGE_SIZE / 2) { ut_ad(!buf_block); @@ -495,6 +497,14 @@ mem_heap_block_free( buf_block_free(buf_block); } #else /* !UNIV_HOTBACKUP */ +#ifdef UNIV_MEM_DEBUG + /* In the debug version we set the memory to a random + combination of hex 0xDE and 0xAD. */ + + mem_erase_buf((byte*)block, len); +#else /* UNIV_MEM_DEBUG */ + UNIV_MEM_ASSERT_AND_FREE(block, len); +#endif /* UNIV_MEM_DEBUG */ ut_free(block); #endif /* !UNIV_HOTBACKUP */ } diff --git a/storage/innodb_plugin/mtr/mtr0mtr.c b/storage/innodb_plugin/mtr/mtr0mtr.c index be31c5df801..417e97732bb 100644 --- a/storage/innodb_plugin/mtr/mtr0mtr.c +++ b/storage/innodb_plugin/mtr/mtr0mtr.c @@ -35,6 +35,7 @@ Created 11/26/1995 Heikki Tuuri #include "log0log.h" #ifndef UNIV_HOTBACKUP +# include "log0recv.h" /*****************************************************************//** Releases the item in the slot given. */ UNIV_INLINE @@ -115,7 +116,6 @@ mtr_log_reserve_and_write( dyn_array_t* mlog; dyn_block_t* block; ulint data_size; - ibool success; byte* first_data; ut_ad(mtr); @@ -134,8 +134,8 @@ mtr_log_reserve_and_write( if (mlog->heap == NULL) { mtr->end_lsn = log_reserve_and_write_fast( first_data, dyn_block_get_used(mlog), - &(mtr->start_lsn), &success); - if (success) { + &mtr->start_lsn); + if (mtr->end_lsn) { return; } @@ -182,6 +182,8 @@ mtr_commit( ut_d(mtr->state = MTR_COMMITTING); #ifndef UNIV_HOTBACKUP + /* This is a dirty read, for debugging. */ + ut_ad(!recv_no_log_write); write_log = mtr->modifications && mtr->n_log_recs; if (write_log) { diff --git a/storage/innodb_plugin/mysql-test/innodb-analyze.test b/storage/innodb_plugin/mysql-test/innodb-analyze.test index d5d6d698170..9bdb9db697c 100644 --- a/storage/innodb_plugin/mysql-test/innodb-analyze.test +++ b/storage/innodb_plugin/mysql-test/innodb-analyze.test @@ -11,6 +11,7 @@ -- disable_result_log -- enable_warnings +let $sample_pages=`select @@innodb_stats_sample_pages`; SET GLOBAL innodb_stats_sample_pages=0; # check that the value has been adjusted to 1 @@ -61,3 +62,4 @@ SET GLOBAL innodb_stats_sample_pages=16; ANALYZE TABLE innodb_analyze; DROP TABLE innodb_analyze; +EVAL SET GLOBAL innodb_stats_sample_pages=$sample_pages; diff --git a/storage/innodb_plugin/mysql-test/innodb-consistent-master.opt b/storage/innodb_plugin/mysql-test/innodb-consistent-master.opt new file mode 100644 index 00000000000..8cca44767da --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb-consistent-master.opt @@ -0,0 +1 @@ +--innodb_lock_wait_timeout=2
diff --git a/storage/innodb_plugin/mysql-test/innodb-consistent.result b/storage/innodb_plugin/mysql-test/innodb-consistent.result new file mode 100644 index 00000000000..9115791b99c --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb-consistent.result @@ -0,0 +1,35 @@ +drop table if exists t1; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +create table t2 like t1; +insert into t2 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; +begin; +replace into t1 select * from t2; +set session transaction isolation level read committed; +set autocommit=0; +delete from t2 where a=5; +commit; +delete from t2; +commit; +commit; +begin; +insert into t1 select * from t2; +set session transaction isolation level read committed; +set autocommit=0; +delete from t2 where a=5; +commit; +delete from t2; +commit; +commit; +select * from t1; +a +1 +2 +3 +4 +5 +6 +7 +drop table t1; +drop table t2; diff --git a/storage/innodb_plugin/mysql-test/innodb-consistent.test b/storage/innodb_plugin/mysql-test/innodb-consistent.test new file mode 100644 index 00000000000..791600fc8a7 --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb-consistent.test @@ -0,0 +1,58 @@ +-- source include/not_embedded.inc
+-- source include/have_innodb.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+# REPLACE INTO ... SELECT and INSERT INTO ... SELECT should do
+# a consistent read of the source table.
+
+connect (a,localhost,root,,);
+connect (b,localhost,root,,);
+connection a;
+set session transaction isolation level read committed;
+create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
+create table t2 like t1;
+insert into t2 values (1),(2),(3),(4),(5),(6),(7);
+set autocommit=0;
+
+# REPLACE INTO ... SELECT case
+begin;
+# this should not result in any locks on t2.
+replace into t1 select * from t2;
+
+connection b;
+set session transaction isolation level read committed;
+set autocommit=0;
+# should not cuase a lock wait.
+delete from t2 where a=5;
+commit;
+delete from t2;
+commit;
+connection a;
+commit;
+
+# INSERT INTO ... SELECT case
+begin;
+# this should not result in any locks on t2.
+insert into t1 select * from t2;
+
+connection b;
+set session transaction isolation level read committed;
+set autocommit=0;
+# should not cuase a lock wait.
+delete from t2 where a=5;
+commit;
+delete from t2;
+commit;
+connection a;
+commit;
+
+select * from t1;
+drop table t1;
+drop table t2;
+
+connection default;
+disconnect a;
+disconnect b;
diff --git a/storage/innodb_plugin/mysql-test/innodb-zip.result b/storage/innodb_plugin/mysql-test/innodb-zip.result index c81401743a5..b26c4112826 100644 --- a/storage/innodb_plugin/mysql-test/innodb-zip.result +++ b/storage/innodb_plugin/mysql-test/innodb-zip.result @@ -141,7 +141,7 @@ drop table t1; CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439))) +CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); DROP TABLE t1; diff --git a/storage/innodb_plugin/mysql-test/innodb-zip.test b/storage/innodb_plugin/mysql-test/innodb-zip.test index ddc39d44487..5bcd0e3c824 100644 --- a/storage/innodb_plugin/mysql-test/innodb-zip.test +++ b/storage/innodb_plugin/mysql-test/innodb-zip.test @@ -105,7 +105,7 @@ drop table t1; --error ER_TOO_BIG_ROWSIZE CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439))) +CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); DROP TABLE t1; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug34300.test b/storage/innodb_plugin/mysql-test/innodb_bug34300.test index 114bcf98c25..68c385fd72a 100644 --- a/storage/innodb_plugin/mysql-test/innodb_bug34300.test +++ b/storage/innodb_plugin/mysql-test/innodb_bug34300.test @@ -9,6 +9,7 @@ -- disable_result_log # set packet size and reconnect +let $max_packet=`select @@global.max_allowed_packet`; SET @@global.max_allowed_packet=16777216; --connect (newconn, localhost, root,,) @@ -30,3 +31,4 @@ ALTER TABLE bug34300 ADD COLUMN (f10 INT); SELECT f4, f8 FROM bug34300; DROP TABLE bug34300; +EVAL SET @@global.max_allowed_packet=$max_packet; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug36169.test b/storage/innodb_plugin/mysql-test/innodb_bug36169.test index d3566d3eb39..5bf55193b5c 100644 --- a/storage/innodb_plugin/mysql-test/innodb_bug36169.test +++ b/storage/innodb_plugin/mysql-test/innodb_bug36169.test @@ -5,6 +5,8 @@ -- source include/have_innodb.inc +let $file_format=`select @@innodb_file_format`; +let $file_per_table=`select @@innodb_file_per_table`; SET GLOBAL innodb_file_format='Barracuda'; SET GLOBAL innodb_file_per_table=ON; @@ -1153,3 +1155,5 @@ DROP TABLE IF EXISTS table4; DROP TABLE IF EXISTS table5; DROP TABLE IF EXISTS table6; +EVAL SET GLOBAL innodb_file_format=$file_format; +EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug36172.test b/storage/innodb_plugin/mysql-test/innodb_bug36172.test index 666d4a2f4b7..c6c4e6fae47 100644 --- a/storage/innodb_plugin/mysql-test/innodb_bug36172.test +++ b/storage/innodb_plugin/mysql-test/innodb_bug36172.test @@ -14,6 +14,9 @@ SET storage_engine=InnoDB; -- disable_query_log -- disable_result_log +let $file_format=`select @@innodb_file_format`; +let $file_format_check=`select @@innodb_file_format_check`; +let $file_per_table=`select @@innodb_file_per_table`; SET GLOBAL innodb_file_format='Barracuda'; SET GLOBAL innodb_file_per_table=on; @@ -24,3 +27,6 @@ CHECK TABLE table0 EXTENDED; INSERT IGNORE INTO `table0` SET `col19` = '19940127002709', `col20` = 2383927.9055146948, `col21` = 4293243420.5621204000, `col22` = '20511211123705', `col23` = 4289899778.6573381000, `col24` = 4293449279.0540481000, `col25` = 'emphysemic', `col26` = 'dentally', `col27` = '2347406', `col28` = 'eruct', `col30` = 1222, `col31` = 4294372994.9941406000, `col32` = 4291385574.1173744000, `col33` = 'borrowing\'s', `col34` = 'septics', `col35` = 'ratter\'s', `col36` = 'Kaye', `col37` = 'Florentia', `col38` = 'allium', `col39` = 'barkeep', `col40` = '19510407003441', `col41` = 4293559200.4215522000, `col42` = 22482, `col43` = 'decussate', `col44` = 'Brom\'s', `col45` = 'violated', `col46` = 4925506.4635456400, `col47` = 930549, `col48` = '51296066', `col49` = 'voluminously', `col50` = '29306676', `col51` = -88, `col52` = -2153690, `col53` = 4290250202.1464887000, `col54` = 'expropriation', `col55` = 'Aberdeen\'s', `col56` = 20343, `col58` = '19640415171532', `col59` = 'extern', `col60` = 'Ubana', `col61` = 4290487961.8539081000, `col62` = '2147', `col63` = -24271, `col64` = '20750801194548', `col65` = 'Cunaxa\'s', `col66` = 'pasticcio', `col67` = 2795817, `col68` = 'Indore\'s', `col70` = 6864127, `col71` = '1817832', `col72` = '20540506114211', `col73` = '20040101012300', `col74` = 'rationalized', `col75` = '45522', `col76` = 'indene', `col77` = -6964559, `col78` = 4247535.5266884370, `col79` = '20720416124357', `col80` = '2143', `col81` = 4292060102.4466386000, `col82` = 'striving', `col83` = 'boneblack\'s', `col84` = 'redolent', `col85` = 6489697.9009369183, `col86` = 4287473465.9731131000, `col87` = 7726015, `col88` = 'perplexed', `col89` = '17153791', `col90` = 5478587.1108127078, `col91` = 4287091404.7004304000, `col92` = 'Boulez\'s', `col93` = '2931278'; CHECK TABLE table0 EXTENDED; DROP TABLE table0; +EVAL SET GLOBAL innodb_file_format=$file_format; +EVAL SET GLOBAL innodb_file_format_check=$file_format_check; +EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug44369.result b/storage/innodb_plugin/mysql-test/innodb_bug44369.result new file mode 100644 index 00000000000..e4b84ecac19 --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb_bug44369.result @@ -0,0 +1,14 @@ +create table bug44369 (DB_ROW_ID int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +create table bug44369 (db_row_id int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +show errors; +Level Code Message +Error 1005 Error creating table 'test/bug44369' with column name 'db_row_id'. 'db_row_id' is a reserved name. Please try to re-create the table with a different column name. +Error 1005 Can't create table 'test.bug44369' (errno: -1) +create table bug44369 (db_TRX_Id int) engine=innodb; +ERROR HY000: Can't create table 'test.bug44369' (errno: -1) +show errors; +Level Code Message +Error 1005 Error creating table 'test/bug44369' with column name 'db_TRX_Id'. 'db_TRX_Id' is a reserved name. Please try to re-create the table with a different column name. +Error 1005 Can't create table 'test.bug44369' (errno: -1) diff --git a/storage/innodb_plugin/mysql-test/innodb_bug44369.test b/storage/innodb_plugin/mysql-test/innodb_bug44369.test new file mode 100644 index 00000000000..495059eb5e6 --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb_bug44369.test @@ -0,0 +1,21 @@ +# This is the test for bug 44369. We should +# block table creation with columns match +# some innodb internal reserved key words, +# both case sensitively and insensitely. + +--source include/have_innodb.inc + +# This create table operation should fail. +--error ER_CANT_CREATE_TABLE +create table bug44369 (DB_ROW_ID int) engine=innodb; + +# This create should fail as well +--error ER_CANT_CREATE_TABLE +create table bug44369 (db_row_id int) engine=innodb; + +show errors; + +--error ER_CANT_CREATE_TABLE +create table bug44369 (db_TRX_Id int) engine=innodb; + +show errors; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug44571.result b/storage/innodb_plugin/mysql-test/innodb_bug44571.result new file mode 100644 index 00000000000..36374edcb3e --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb_bug44571.result @@ -0,0 +1,9 @@ +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +ERROR 42000: Key column 'foo' doesn't exist in table +ALTER TABLE bug44571 ADD INDEX bug44571b (bar); +ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it +CREATE INDEX bug44571b ON bug44571 (bar); +ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it +DROP TABLE bug44571; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug44571.test b/storage/innodb_plugin/mysql-test/innodb_bug44571.test new file mode 100644 index 00000000000..685463ceff9 --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb_bug44571.test @@ -0,0 +1,17 @@ +# +# Bug#44571 InnoDB Plugin crashes on ADD INDEX +# http://bugs.mysql.com/44571 +# +-- source include/have_innodb.inc + +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +-- error ER_KEY_COLUMN_DOES_NOT_EXITS +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +# The following will fail, because the CHANGE foo bar was +# not communicated to InnoDB. +--error ER_NOT_KEYFILE +ALTER TABLE bug44571 ADD INDEX bug44571b (bar); +--error ER_NOT_KEYFILE +CREATE INDEX bug44571b ON bug44571 (bar); +DROP TABLE bug44571; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug46000.result b/storage/innodb_plugin/mysql-test/innodb_bug46000.result new file mode 100644 index 00000000000..ccff888a48d --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb_bug46000.result @@ -0,0 +1,17 @@ +create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; +ERROR HY000: Can't create table 'test.bug46000' (errno: -1) +create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; +ERROR HY000: Can't create table 'test.bug46000' (errno: -1) +show errors; +Level Code Message +Error 1005 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. +Error 1005 Can't create table 'test.bug46000' (errno: -1) +create table bug46000(id int) engine=innodb; +create index GEN_CLUST_INDEX on bug46000(id); +ERROR HY000: Can't create table '#sql-temporary' (errno: -1) +show errors; +Level Code Message +Error 1005 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. +Error 1005 Can't create table '#sql-temporary' (errno: -1) +create index idx on bug46000(id); +drop table bug46000; diff --git a/storage/innodb_plugin/mysql-test/innodb_bug46000.test b/storage/innodb_plugin/mysql-test/innodb_bug46000.test new file mode 100644 index 00000000000..80c18c58ef0 --- /dev/null +++ b/storage/innodb_plugin/mysql-test/innodb_bug46000.test @@ -0,0 +1,34 @@ +# This is the test for bug 46000. We shall +# block any index creation with the name of +# "GEN_CLUST_INDEX", which is the reserved +# name for innodb default primary index. + +--source include/have_innodb.inc + +# This 'create table' operation should fail because of +# using the reserve name as its index name. +--error ER_CANT_CREATE_TABLE +create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; + +# Mixed upper/lower case of the reserved key words +--error ER_CANT_CREATE_TABLE +create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; + +show errors; + +create table bug46000(id int) engine=innodb; + +# This 'create index' operation should fail. +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +create index GEN_CLUST_INDEX on bug46000(id); + +--replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ +show errors; + +# This 'create index' operation should succeed, no +# temp table left from last failed create index +# operation. +create index idx on bug46000(id); + +drop table bug46000; diff --git a/storage/innodb_plugin/mysql-test/innodb_file_format.result b/storage/innodb_plugin/mysql-test/innodb_file_format.result index 9cfac5f001c..8e9a317308b 100644 --- a/storage/innodb_plugin/mysql-test/innodb_file_format.result +++ b/storage/innodb_plugin/mysql-test/innodb_file_format.result @@ -42,3 +42,4 @@ ERROR HY000: Incorrect arguments to SET select @@innodb_file_format_check; @@innodb_file_format_check Barracuda +set global innodb_file_format_check=antelope; diff --git a/storage/innodb_plugin/mysql-test/innodb_file_format.test b/storage/innodb_plugin/mysql-test/innodb_file_format.test index 62ce4157183..d63c9b0228f 100644 --- a/storage/innodb_plugin/mysql-test/innodb_file_format.test +++ b/storage/innodb_plugin/mysql-test/innodb_file_format.test @@ -26,3 +26,4 @@ set global innodb_file_format=on; --error ER_WRONG_ARGUMENTS set global innodb_file_format=off; select @@innodb_file_format_check; +set global innodb_file_format_check=antelope; diff --git a/storage/innodb_plugin/os/os0file.c b/storage/innodb_plugin/os/os0file.c index d3bd6465f5f..0cb76d1796f 100644 --- a/storage/innodb_plugin/os/os0file.c +++ b/storage/innodb_plugin/os/os0file.c @@ -88,7 +88,9 @@ UNIV_INTERN ibool os_do_not_call_flush_at_each_write = FALSE; /* We do not call os_file_flush in every os_file_write. */ #endif /* UNIV_DO_FLUSH */ -#ifndef UNIV_HOTBACKUP +#ifdef UNIV_HOTBACKUP +# define os_aio_use_native_aio FALSE +#else /* UNIV_HOTBACKUP */ /* We use these mutexes to protect lseek + file i/o operation, if the OS does not provide an atomic pread or pwrite, or similar */ #define OS_FILE_N_SEEK_MUTEXES 16 @@ -198,7 +200,7 @@ static ulint os_aio_n_segments = ULINT_UNDEFINED; /** If the following is TRUE, read i/o handler threads try to wait until a batch of new read requests have been posted */ static ibool os_aio_recommend_sleep_for_read_threads = FALSE; -#endif /* !UNIV_HOTBACKUP */ +#endif /* UNIV_HOTBACKUP */ UNIV_INTERN ulint os_n_file_reads = 0; UNIV_INTERN ulint os_bytes_read_since_printout = 0; @@ -315,6 +317,12 @@ os_file_get_last_error( " software or another instance\n" "InnoDB: of MySQL." " Please close it to get rid of this error.\n"); + } else if (err == ERROR_WORKING_SET_QUOTA + || err == ERROR_NO_SYSTEM_RESOURCES) { + fprintf(stderr, + "InnoDB: The error means that there are no" + " sufficient system resources or quota to" + " complete the operation.\n"); } else { fprintf(stderr, "InnoDB: Some operating system error numbers" @@ -336,6 +344,9 @@ os_file_get_last_error( } else if (err == ERROR_SHARING_VIOLATION || err == ERROR_LOCK_VIOLATION) { return(OS_FILE_SHARING_VIOLATION); + } else if (err == ERROR_WORKING_SET_QUOTA + || err == ERROR_NO_SYSTEM_RESOURCES) { + return(OS_FILE_INSUFFICIENT_RESOURCE); } else { return(100 + err); } @@ -454,6 +465,10 @@ os_file_handle_error_cond_exit( os_thread_sleep(10000000); /* 10 sec */ return(TRUE); + } else if (err == OS_FILE_INSUFFICIENT_RESOURCE) { + + os_thread_sleep(100000); /* 100 ms */ + return(TRUE); } else { if (name) { fprintf(stderr, "InnoDB: File name %s\n", name); @@ -817,6 +832,23 @@ next_file: ret = stat(full_path, &statinfo); if (ret) { + + if (errno == ENOENT) { + /* readdir() returned a file that does not exist, + it must have been deleted in the meantime. Do what + would have happened if the file was deleted before + readdir() - ignore and go to the next entry. + If this is the last entry then info->name will still + contain the name of the deleted file when this + function returns, but this is not an issue since the + caller shouldn't be looking at info when end of + directory is returned. */ + + ut_free(full_path); + + goto next_file; + } + os_file_handle_error_no_exit(full_path, "stat"); ut_free(full_path); @@ -1245,6 +1277,7 @@ try_again: } #endif #ifdef UNIV_NON_BUFFERED_IO +# ifndef UNIV_HOTBACKUP if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) { /* Do not use unbuffered i/o to log files because value 2 denotes that we do not flush the log at every @@ -1253,10 +1286,14 @@ try_again: == SRV_WIN_IO_UNBUFFERED) { attributes = attributes | FILE_FLAG_NO_BUFFERING; } -#endif +# else /* !UNIV_HOTBACKUP */ + attributes = attributes | FILE_FLAG_NO_BUFFERING; +# endif /* !UNIV_HOTBACKUP */ +#endif /* UNIV_NON_BUFFERED_IO */ } else if (purpose == OS_FILE_NORMAL) { attributes = 0; #ifdef UNIV_NON_BUFFERED_IO +# ifndef UNIV_HOTBACKUP if (type == OS_LOG_FILE && srv_flush_log_at_trx_commit == 2) { /* Do not use unbuffered i/o to log files because value 2 denotes that we do not flush the log at every @@ -1265,7 +1302,10 @@ try_again: == SRV_WIN_IO_UNBUFFERED) { attributes = attributes | FILE_FLAG_NO_BUFFERING; } -#endif +# else /* !UNIV_HOTBACKUP */ + attributes = attributes | FILE_FLAG_NO_BUFFERING; +# endif /* !UNIV_HOTBACKUP */ +#endif /* UNIV_NON_BUFFERED_IO */ } else { attributes = 0; ut_error; @@ -2022,7 +2062,9 @@ os_file_pread( offset */ { off_t offs; +#if defined(HAVE_PREAD) && !defined(HAVE_BROKEN_PREAD) ssize_t n_bytes; +#endif /* HAVE_PREAD && !HAVE_BROKEN_PREAD */ ut_a((offset & 0xFFFFFFFFUL) == offset); @@ -2061,16 +2103,20 @@ os_file_pread( { off_t ret_offset; ssize_t ret; +#ifndef UNIV_HOTBACKUP ulint i; +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads++; os_mutex_exit(os_file_count_mutex); +#ifndef UNIV_HOTBACKUP /* Protect the seek / read operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ ret_offset = lseek(file, offs, SEEK_SET); @@ -2080,7 +2126,9 @@ os_file_pread( ret = read(file, buf, (ssize_t)n); } +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2158,16 +2206,20 @@ os_file_pwrite( #else { off_t ret_offset; +# ifndef UNIV_HOTBACKUP ulint i; +# endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_writes++; os_mutex_exit(os_file_count_mutex); +# ifndef UNIV_HOTBACKUP /* Protect the seek / write operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +# endif /* UNIV_HOTBACKUP */ ret_offset = lseek(file, offs, SEEK_SET); @@ -2193,7 +2245,9 @@ os_file_pwrite( # endif /* UNIV_DO_FLUSH */ func_exit: +# ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +# endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_writes--; @@ -2227,7 +2281,9 @@ os_file_read( DWORD low; DWORD high; ibool retry; +#ifndef UNIV_HOTBACKUP ulint i; +#endif /* !UNIV_HOTBACKUP */ ut_a((offset & 0xFFFFFFFFUL) == offset); @@ -2246,16 +2302,20 @@ try_again: os_n_pending_reads++; os_mutex_exit(os_file_count_mutex); +#ifndef UNIV_HOTBACKUP /* Protect the seek / read operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ ret2 = SetFilePointer(file, low, &high, FILE_BEGIN); if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) { +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2266,7 +2326,9 @@ try_again: ret = ReadFile(file, buf, (DWORD) n, &len, NULL); +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2275,7 +2337,7 @@ try_again: if (ret && len == n) { return(TRUE); } -#else +#else /* __WIN__ */ ibool retry; ssize_t ret; @@ -2294,7 +2356,7 @@ try_again: "InnoDB: Was only able to read %ld.\n", (ulong)n, (ulong)offset_high, (ulong)offset, (long)ret); -#endif +#endif /* __WIN__ */ #ifdef __WIN__ error_handling: #endif @@ -2343,7 +2405,9 @@ os_file_read_no_error_handling( DWORD low; DWORD high; ibool retry; +#ifndef UNIV_HOTBACKUP ulint i; +#endif /* !UNIV_HOTBACKUP */ ut_a((offset & 0xFFFFFFFFUL) == offset); @@ -2362,16 +2426,20 @@ try_again: os_n_pending_reads++; os_mutex_exit(os_file_count_mutex); +#ifndef UNIV_HOTBACKUP /* Protect the seek / read operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ ret2 = SetFilePointer(file, low, &high, FILE_BEGIN); if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) { +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2382,7 +2450,9 @@ try_again: ret = ReadFile(file, buf, (DWORD) n, &len, NULL); +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_reads--; @@ -2391,7 +2461,7 @@ try_again: if (ret && len == n) { return(TRUE); } -#else +#else /* __WIN__ */ ibool retry; ssize_t ret; @@ -2404,7 +2474,7 @@ try_again: return(TRUE); } -#endif +#endif /* __WIN__ */ #ifdef __WIN__ error_handling: #endif @@ -2463,9 +2533,11 @@ os_file_write( DWORD ret2; DWORD low; DWORD high; - ulint i; ulint n_retries = 0; ulint err; +#ifndef UNIV_HOTBACKUP + ulint i; +#endif /* !UNIV_HOTBACKUP */ ut_a((offset & 0xFFFFFFFF) == offset); @@ -2482,16 +2554,20 @@ retry: os_n_pending_writes++; os_mutex_exit(os_file_count_mutex); +#ifndef UNIV_HOTBACKUP /* Protect the seek / write operation with a mutex */ i = ((ulint) file) % OS_FILE_N_SEEK_MUTEXES; os_mutex_enter(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ ret2 = SetFilePointer(file, low, &high, FILE_BEGIN); if (ret2 == 0xFFFFFFFF && GetLastError() != NO_ERROR) { +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_writes--; @@ -2525,7 +2601,9 @@ retry: } # endif /* UNIV_DO_FLUSH */ +#ifndef UNIV_HOTBACKUP os_mutex_exit(os_file_seek_mutexes[i]); +#endif /* !UNIV_HOTBACKUP */ os_mutex_enter(os_file_count_mutex); os_n_pending_writes--; @@ -3371,9 +3449,21 @@ void os_aio_simulated_put_read_threads_to_sleep(void) /*============================================*/ { + +/* The idea of putting background IO threads to sleep is only for +Windows when using simulated AIO. Windows XP seems to schedule +background threads too eagerly to allow for coalescing during +readahead requests. */ +#ifdef __WIN__ os_aio_array_t* array; ulint g; + if (os_aio_use_native_aio) { + /* We do not use simulated aio: do nothing */ + + return; + } + os_aio_recommend_sleep_for_read_threads = TRUE; for (g = 0; g < os_aio_n_segments; g++) { @@ -3384,6 +3474,7 @@ os_aio_simulated_put_read_threads_to_sleep(void) os_event_reset(os_aio_segment_wait_events[g]); } } +#endif /* __WIN__ */ } /*******************************************************************//** diff --git a/storage/innodb_plugin/os/os0proc.c b/storage/innodb_plugin/os/os0proc.c index a0ea9a1b258..48922886f23 100644 --- a/storage/innodb_plugin/os/os0proc.c +++ b/storage/innodb_plugin/os/os0proc.c @@ -97,6 +97,7 @@ os_mem_alloc_large( fprintf(stderr, "InnoDB: HugeTLB: Warning: Failed to" " attach shared memory segment, errno %d\n", errno); + ptr = NULL; } /* Remove the shared memory segment so that it will be diff --git a/storage/innodb_plugin/page/page0cur.c b/storage/innodb_plugin/page/page0cur.c index 65f3ba67439..f10f16a7dd9 100644 --- a/storage/innodb_plugin/page/page0cur.c +++ b/storage/innodb_plugin/page/page0cur.c @@ -1195,7 +1195,7 @@ page_cur_insert_rec_zip_reorg( } /* Out of space: restore the page */ - if (!page_zip_decompress(page_zip, page)) { + if (!page_zip_decompress(page_zip, page, FALSE)) { ut_error; /* Memory corrupted? */ } ut_ad(page_validate(page, index)); diff --git a/storage/innodb_plugin/page/page0page.c b/storage/innodb_plugin/page/page0page.c index f056ef77bdc..ab2ba60570e 100644 --- a/storage/innodb_plugin/page/page0page.c +++ b/storage/innodb_plugin/page/page0page.c @@ -45,7 +45,7 @@ Created 2/2/1994 Heikki Tuuri ============== The index page consists of a page header which contains the page's -id and other information. On top of it are the the index records +id and other information. On top of it are the index records in a heap linked into a one way linear list according to alphabetic order. Just below page end is an array of pointers which we call page directory, @@ -679,7 +679,7 @@ page_copy_rec_list_end( if (UNIV_UNLIKELY (!page_zip_decompress(new_page_zip, - new_page))) { + new_page, FALSE))) { ut_error; } ut_ad(page_validate(new_page, index)); @@ -792,7 +792,7 @@ page_copy_rec_list_start( if (UNIV_UNLIKELY (!page_zip_decompress(new_page_zip, - new_page))) { + new_page, FALSE))) { ut_error; } ut_ad(page_validate(new_page, index)); diff --git a/storage/innodb_plugin/page/page0zip.c b/storage/innodb_plugin/page/page0zip.c index 92ba0ec768a..aa5e39ff04a 100644 --- a/storage/innodb_plugin/page/page0zip.c +++ b/storage/innodb_plugin/page/page0zip.c @@ -47,8 +47,10 @@ Created June 2005 by Marko Makela # define buf_LRU_stat_inc_unzip() ((void) 0) #endif /* !UNIV_HOTBACKUP */ +#ifndef UNIV_HOTBACKUP /** Statistics on compression, indexed by page_zip_des_t::ssize - 1 */ UNIV_INTERN page_zip_stat_t page_zip_stat[PAGE_ZIP_NUM_SSIZE - 1]; +#endif /* !UNIV_HOTBACKUP */ /* Please refer to ../include/page0zip.ic for a description of the compressed page format. */ @@ -1144,7 +1146,9 @@ page_zip_compress( ulint* offsets = NULL; ulint n_blobs = 0; byte* storage;/* storage of uncompressed columns */ +#ifndef UNIV_HOTBACKUP ullint usec = ut_time_us(NULL); +#endif /* !UNIV_HOTBACKUP */ #ifdef PAGE_ZIP_COMPRESS_DBG FILE* logfile = NULL; #endif @@ -1208,7 +1212,9 @@ page_zip_compress( } } #endif /* PAGE_ZIP_COMPRESS_DBG */ +#ifndef UNIV_HOTBACKUP page_zip_stat[page_zip->ssize - 1].compressed++; +#endif /* !UNIV_HOTBACKUP */ if (UNIV_UNLIKELY(n_dense * PAGE_ZIP_DIR_SLOT_SIZE >= page_zip_get_size(page_zip))) { @@ -1345,8 +1351,10 @@ err_exit: fclose(logfile); } #endif /* PAGE_ZIP_COMPRESS_DBG */ +#ifndef UNIV_HOTBACKUP page_zip_stat[page_zip->ssize - 1].compressed_usec += ut_time_us(NULL) - usec; +#endif /* !UNIV_HOTBACKUP */ return(FALSE); } @@ -1404,12 +1412,14 @@ err_exit: fclose(logfile); } #endif /* PAGE_ZIP_COMPRESS_DBG */ +#ifndef UNIV_HOTBACKUP { page_zip_stat_t* zip_stat = &page_zip_stat[page_zip->ssize - 1]; zip_stat->compressed_ok++; zip_stat->compressed_usec += ut_time_us(NULL) - usec; } +#endif /* !UNIV_HOTBACKUP */ return(TRUE); } @@ -2811,7 +2821,11 @@ page_zip_decompress( /*================*/ page_zip_des_t* page_zip,/*!< in: data, ssize; out: m_start, m_end, m_nonempty, n_blobs */ - page_t* page) /*!< out: uncompressed page, may be trashed */ + page_t* page, /*!< out: uncompressed page, may be trashed */ + ibool all) /*!< in: TRUE=decompress the whole page; + FALSE=verify but do not copy some + page header fields that should not change + after page creation */ { z_stream d_stream; dict_index_t* index = NULL; @@ -2820,7 +2834,9 @@ page_zip_decompress( ulint trx_id_col = ULINT_UNDEFINED; mem_heap_t* heap; ulint* offsets; +#ifndef UNIV_HOTBACKUP ullint usec = ut_time_us(NULL); +#endif /* !UNIV_HOTBACKUP */ ut_ad(page_zip_simple_validate(page_zip)); UNIV_MEM_ASSERT_W(page, UNIV_PAGE_SIZE); @@ -2839,13 +2855,36 @@ page_zip_decompress( heap = mem_heap_create(n_dense * (3 * sizeof *recs) + UNIV_PAGE_SIZE); recs = mem_heap_alloc(heap, n_dense * (2 * sizeof *recs)); + if (all) { + /* Copy the page header. */ + memcpy(page, page_zip->data, PAGE_DATA); + } else { + /* Check that the bytes that we skip are identical. */ +#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG + ut_a(!memcmp(FIL_PAGE_TYPE + page, + FIL_PAGE_TYPE + page_zip->data, + PAGE_HEADER - FIL_PAGE_TYPE)); + ut_a(!memcmp(PAGE_HEADER + PAGE_LEVEL + page, + PAGE_HEADER + PAGE_LEVEL + page_zip->data, + PAGE_DATA - (PAGE_HEADER + PAGE_LEVEL))); +#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ + + /* Copy the mutable parts of the page header. */ + memcpy(page, page_zip->data, FIL_PAGE_TYPE); + memcpy(PAGE_HEADER + page, PAGE_HEADER + page_zip->data, + PAGE_LEVEL - PAGE_N_DIR_SLOTS); + +#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG + /* Check that the page headers match after copying. */ + ut_a(!memcmp(page, page_zip->data, PAGE_DATA)); +#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ + } + #ifdef UNIV_ZIP_DEBUG - /* Clear the page. */ - memset(page, 0x55, UNIV_PAGE_SIZE); + /* Clear the uncompressed page, except the header. */ + memset(PAGE_DATA + page, 0x55, UNIV_PAGE_SIZE - PAGE_DATA); #endif /* UNIV_ZIP_DEBUG */ - UNIV_MEM_INVALID(page, UNIV_PAGE_SIZE); - /* Copy the page header. */ - memcpy(page, page_zip->data, PAGE_DATA); + UNIV_MEM_INVALID(PAGE_DATA + page, UNIV_PAGE_SIZE - PAGE_DATA); /* Copy the page directory. */ if (UNIV_UNLIKELY(!page_zip_dir_decode(page_zip, page, recs, @@ -2976,12 +3015,14 @@ err_exit: page_zip_fields_free(index); mem_heap_free(heap); +#ifndef UNIV_HOTBACKUP { page_zip_stat_t* zip_stat = &page_zip_stat[page_zip->ssize - 1]; zip_stat->decompressed++; zip_stat->decompressed_usec += ut_time_us(NULL) - usec; } +#endif /* !UNIV_HOTBACKUP */ /* Update the stat counter for LRU policy. */ buf_LRU_stat_inc_unzip(); @@ -3084,7 +3125,7 @@ page_zip_validate_low( #endif /* UNIV_DEBUG_VALGRIND */ temp_page_zip = *page_zip; - valid = page_zip_decompress(&temp_page_zip, temp_page); + valid = page_zip_decompress(&temp_page_zip, temp_page, TRUE); if (!valid) { fputs("page_zip_validate(): failed to decompress\n", stderr); goto func_exit; @@ -4362,8 +4403,8 @@ IMPORTANT: if page_zip_reorganize() is invoked on a leaf page of a non-clustered index, the caller must update the insert buffer free bits in the same mini-transaction in such a way that the modification will be redo-logged. -@return TRUE on success, FALSE on failure; page and page_zip will be -left intact on failure. */ +@return TRUE on success, FALSE on failure; page_zip will be left +intact on failure, but page will be overwritten. */ UNIV_INTERN ibool page_zip_reorganize( @@ -4428,9 +4469,6 @@ page_zip_reorganize( if (UNIV_UNLIKELY(!page_zip_compress(page_zip, page, index, mtr))) { - /* Restore the old page and exit. */ - buf_frame_copy(page, temp_page); - #ifndef UNIV_HOTBACKUP buf_block_free(temp_block); #endif /* !UNIV_HOTBACKUP */ @@ -4591,7 +4629,8 @@ corrupt: memcpy(page_zip->data + page_zip_get_size(page_zip) - trailer_size, ptr + 8 + size, trailer_size); - if (UNIV_UNLIKELY(!page_zip_decompress(page_zip, page))) { + if (UNIV_UNLIKELY(!page_zip_decompress(page_zip, page, + TRUE))) { goto corrupt; } diff --git a/storage/innodb_plugin/plug.in.disabled b/storage/innodb_plugin/plug.in.disabled index 42915ac7426..4ebde50cb35 100644 --- a/storage/innodb_plugin/plug.in.disabled +++ b/storage/innodb_plugin/plug.in.disabled @@ -37,33 +37,75 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ irix*|osf*|sysv5uw7*|openbsd*) CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; *solaris*|*SunOS*) - # Begin Solaris atomic function checks - AC_CHECK_FUNCS(atomic_cas_ulong atomic_cas_32 \ - atomic_cas_64 atomic_add_long, - AC_DEFINE( - [HAVE_SOLARIS_ATOMICS], - [1], - [Define to 1 if Solaris supports \ - atomic functions.])) - ### End Solaris atomic function checks - CFLAGS="$CFLAGS -DUNIV_SOLARIS";; esac + INNODB_DYNAMIC_CFLAGS="-DMYSQL_DYNAMIC_PLUGIN" - case "$target_cpu---$target_os" in - x86_64---*) + + case "$target_cpu" in + x86_64) # The AMD64 ABI forbids absolute addresses in shared libraries ;; - *---solaris*|*---SunOS*) - # Shared objects must be linked from PIC code on Solaris. - ;; - *86---) + *86) # Use absolute addresses on IA-32 INNODB_DYNAMIC_CFLAGS="$INNODB_DYNAMIC_CFLAGS -prefer-non-pic" ;; esac AC_SUBST(INNODB_DYNAMIC_CFLAGS) + + AC_MSG_CHECKING(whether GCC atomic builtins are available) + # either define HAVE_IB_GCC_ATOMIC_BUILTINS or not + AC_TRY_RUN( + [ + int main() + { + long x; + long y; + long res; + char c; + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x, y); + if (!res || x != y) { + return(1); + } + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x + 1, y); + if (res || x != 10) { + return(1); + } + + x = 10; + y = 123; + res = __sync_add_and_fetch(&x, y); + if (res != 123 + 10 || x != 123 + 10) { + return(1); + } + + c = 10; + res = __sync_lock_test_and_set(&c, 123); + if (res != 10 || c != 123) { + return(1); + } + + return(0); + } + ], + [ + AC_DEFINE([HAVE_IB_GCC_ATOMIC_BUILTINS], [1], + [GCC atomic builtins are available]) + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_RESULT(no) + ] + ) + AC_MSG_CHECKING(whether pthread_t can be used by GCC atomic builtins) + # either define HAVE_IB_ATOMIC_PTHREAD_T_GCC or not AC_TRY_RUN( [ #include <pthread.h> @@ -84,47 +126,73 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ } ], [ - AC_DEFINE([HAVE_ATOMIC_PTHREAD_T], [1], + AC_DEFINE([HAVE_IB_ATOMIC_PTHREAD_T_GCC], [1], [pthread_t can be used by GCC atomic builtins]) AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) ] - ) + ) - # Try using solaris atomics on SunOS if GCC atomics are not available - AC_CHECK_DECLS( - [HAVE_ATOMIC_PTHREAD_T], + AC_MSG_CHECKING(whether Solaris libc atomic functions are available) + # either define HAVE_IB_SOLARIS_ATOMICS or not + AC_CHECK_FUNCS(atomic_add_long \ + atomic_cas_32 \ + atomic_cas_64 \ + atomic_cas_ulong, + + AC_DEFINE([HAVE_IB_SOLARIS_ATOMICS], [1], + [Define to 1 if Solaris libc atomic functions \ + are available]) + ) + + AC_MSG_CHECKING(whether pthread_t can be used by Solaris libc atomic functions) + # either define HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS or not + AC_TRY_RUN( [ - AC_MSG_NOTICE(no need to check pthread_t size) + #include <pthread.h> + #include <string.h> + + int main(int argc, char** argv) { + pthread_t x1; + pthread_t x2; + pthread_t x3; + + memset(&x1, 0x0, sizeof(x1)); + memset(&x2, 0x0, sizeof(x2)); + memset(&x3, 0x0, sizeof(x3)); + + if (sizeof(pthread_t) == 4) { + + atomic_cas_32(&x1, x2, x3); + + } else if (sizeof(pthread_t) == 8) { + + atomic_cas_64(&x1, x2, x3); + + } else { + + return(1); + } + + return(0); + } ], [ - AC_CHECK_DECLS( - [HAVE_SOLARIS_ATOMICS], - [ - AC_MSG_CHECKING(checking if pthread_t size is integral) - AC_TRY_RUN( - [ - #include <pthread.h> - int main() - { - pthread_t x = 0; - return(0); - } - ], - [ - AC_DEFINE([HAVE_ATOMIC_PTHREAD_T], [1], + AC_DEFINE([HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS], [1], [pthread_t can be used by solaris atomics]) - AC_MSG_RESULT(yes) - # size of pthread_t is needed for typed solaris atomics - AC_CHECK_SIZEOF([pthread_t], [], [#include <pthread.h>]) - ], - [ - AC_MSG_RESULT(no) - ]) - ]) - ]) + AC_MSG_RESULT(yes) + ], + [ + AC_MSG_RESULT(no) + ] + ) + + # this is needed to know which one of atomic_cas_32() or atomic_cas_64() + # to use in the source + AC_CHECK_SIZEOF([pthread_t], [], [#include <pthread.h>]) + # Check for x86 PAUSE instruction AC_MSG_CHECKING(for x86 PAUSE instruction) # We have to actually try running the test program, because of a bug @@ -141,7 +209,7 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [ } ], [ - AC_DEFINE([IB_HAVE_PAUSE_INSTRUCTION], [1], [Does x86 PAUSE instruction exist]) + AC_DEFINE([HAVE_IB_PAUSE_INSTRUCTION], [1], [Does x86 PAUSE instruction exist]) AC_MSG_RESULT(yes) ], [ diff --git a/storage/innodb_plugin/rem/rem0cmp.c b/storage/innodb_plugin/rem/rem0cmp.c index b707f2116d6..e6dab0bc66b 100644 --- a/storage/innodb_plugin/rem/rem0cmp.c +++ b/storage/innodb_plugin/rem/rem0cmp.c @@ -36,7 +36,7 @@ Created 7/1/1994 Heikki Tuuri The records are put into alphabetical order in the following way: let F be the first field where two records disagree. -If there is a character in some position n where the the +If there is a character in some position n where the records disagree, the order is determined by comparison of the characters at position n, possibly after collating transformation. If there is no such character, @@ -76,7 +76,7 @@ cmp_debug_dtuple_rec_with_match( /*************************************************************//** This function is used to compare two data fields for which the data type is such that we must use MySQL code to compare them. The prototype here -must be a copy of the the one in ha_innobase.cc! +must be a copy of the one in ha_innobase.cc! @return 1, 0, -1, if a is greater, equal, less than b, respectively */ extern int @@ -399,7 +399,7 @@ next_byte: /*************************************************************//** This function is used to compare a data tuple to a physical record. Only dtuple->n_fields_cmp first fields are taken into account for -the the data tuple! If we denote by n = n_fields_cmp, then rec must +the data tuple! If we denote by n = n_fields_cmp, then rec must have either m >= n fields, or it must differ from dtuple in some of the m fields rec has. If rec has an externally stored field we do not compare it but return with value 0 if such a comparison should be diff --git a/storage/innodb_plugin/revert_gen.sh b/storage/innodb_plugin/revert_gen.sh new file mode 100755 index 00000000000..231e05a21e0 --- /dev/null +++ b/storage/innodb_plugin/revert_gen.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# +# revert changes to all generated files. this is useful in some situations +# when merging changes between branches. + +set -eu + +svn revert include/pars0grm.h pars/pars0grm.h pars/lexyy.c pars/pars0grm.c diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index 930c9ec1fc7..fe51fce82c4 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -141,7 +141,7 @@ row_ins_alloc_sys_fields( dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); - ptr = mem_heap_alloc(heap, DATA_ROW_ID_LEN); + ptr = mem_heap_zalloc(heap, DATA_ROW_ID_LEN); dfield_set_data(dfield, ptr, DATA_ROW_ID_LEN); @@ -152,7 +152,7 @@ row_ins_alloc_sys_fields( col = dict_table_get_sys_col(table, DATA_TRX_ID); dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); - ptr = mem_heap_alloc(heap, DATA_TRX_ID_LEN); + ptr = mem_heap_zalloc(heap, DATA_TRX_ID_LEN); dfield_set_data(dfield, ptr, DATA_TRX_ID_LEN); @@ -163,7 +163,7 @@ row_ins_alloc_sys_fields( col = dict_table_get_sys_col(table, DATA_ROLL_PTR); dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); - ptr = mem_heap_alloc(heap, DATA_ROLL_PTR_LEN); + ptr = mem_heap_zalloc(heap, DATA_ROLL_PTR_LEN); dfield_set_data(dfield, ptr, DATA_ROLL_PTR_LEN); } @@ -1191,7 +1191,7 @@ row_ins_check_foreign_constraint( /*=============================*/ ibool check_ref,/*!< in: TRUE if we want to check that the referenced table is ok, FALSE if we - want to to check the foreign key table */ + want to check the foreign key table */ dict_foreign_t* foreign,/*!< in: foreign constraint; NOTE that the tables mentioned in it must be in the dictionary cache if they exist at all */ diff --git a/storage/innodb_plugin/row/row0merge.c b/storage/innodb_plugin/row/row0merge.c index 05a45dc647c..a303a2f3278 100644 --- a/storage/innodb_plugin/row/row0merge.c +++ b/storage/innodb_plugin/row/row0merge.c @@ -60,9 +60,19 @@ Completed by Sunny Bains and Marko Makela #ifdef UNIV_DEBUG /** Set these in order ot enable debug printout. */ /* @{ */ +/** Log the outcome of each row_merge_cmp() call, comparing records. */ static ibool row_merge_print_cmp; +/** Log each record read from temporary file. */ static ibool row_merge_print_read; +/** Log each record write to temporary file. */ static ibool row_merge_print_write; +/** Log each row_merge_blocks() call, merging two blocks of records to +a bigger one. */ +static ibool row_merge_print_block; +/** Log each block read from temporary file. */ +static ibool row_merge_print_block_read; +/** Log each block read from temporary file. */ +static ibool row_merge_print_block_write; /* @} */ #endif /* UNIV_DEBUG */ @@ -109,8 +119,9 @@ typedef struct row_merge_buf_struct row_merge_buf_t; /** Information about temporary files used in merge sort */ struct merge_file_struct { - int fd; /*!< file descriptor */ - ulint offset; /*!< file offset */ + int fd; /*!< file descriptor */ + ulint offset; /*!< file offset (end of file) */ + ib_uint64_t n_rec; /*!< number of records in the file */ }; /** Information about temporary files used in merge sort */ @@ -682,6 +693,13 @@ row_merge_read( ib_uint64_t ofs = ((ib_uint64_t) offset) * sizeof *buf; ibool success; +#ifdef UNIV_DEBUG + if (row_merge_print_block_read) { + fprintf(stderr, "row_merge_read fd=%d ofs=%lu\n", + fd, (ulong) offset); + } +#endif /* UNIV_DEBUG */ + success = os_file_read_no_error_handling(OS_FILE_FROM_FD(fd), buf, (ulint) (ofs & 0xFFFFFFFF), (ulint) (ofs >> 32), @@ -709,6 +727,13 @@ row_merge_write( ib_uint64_t ofs = ((ib_uint64_t) offset) * sizeof(row_merge_block_t); +#ifdef UNIV_DEBUG + if (row_merge_print_block_write) { + fprintf(stderr, "row_merge_write fd=%d ofs=%lu\n", + fd, (ulong) offset); + } +#endif /* UNIV_DEBUG */ + return(UNIV_LIKELY(os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf, (ulint) (ofs & 0xFFFFFFFF), (ulint) (ofs >> 32), @@ -718,7 +743,7 @@ row_merge_write( /********************************************************************//** Read a merge record. @return pointer to next record, or NULL on I/O error or end of list */ -static +static __attribute__((nonnull)) const byte* row_merge_read_rec( /*===============*/ @@ -1070,7 +1095,7 @@ row_merge_cmp( Reads clustered index of the table and create temporary files containing the index entries for the indexes to be built. @return DB_SUCCESS or error */ -static +static __attribute__((nonnull)) ulint row_merge_read_clustered_index( /*===========================*/ @@ -1233,6 +1258,7 @@ row_merge_read_clustered_index( if (UNIV_LIKELY (row && row_merge_buf_add(buf, row, ext))) { + file->n_rec++; continue; } @@ -1274,14 +1300,19 @@ err_exit: UNIV_MEM_INVALID(block[0], sizeof block[0]); merge_buf[i] = row_merge_buf_empty(buf); - /* Try writing the record again, now that - the buffer has been written out and emptied. */ + if (UNIV_LIKELY(row != NULL)) { + /* Try writing the record again, now + that the buffer has been written out + and emptied. */ - if (UNIV_UNLIKELY - (row && !row_merge_buf_add(buf, row, ext))) { - /* An empty buffer should have enough - room for at least one record. */ - ut_error; + if (UNIV_UNLIKELY + (!row_merge_buf_add(buf, row, ext))) { + /* An empty buffer should have enough + room for at least one record. */ + ut_error; + } + + file->n_rec++; } } @@ -1320,7 +1351,7 @@ func_exit: b2 = row_merge_write_rec(&block[2], &buf[2], b2, \ of->fd, &of->offset, \ mrec##N, offsets##N); \ - if (UNIV_UNLIKELY(!b2)) { \ + if (UNIV_UNLIKELY(!b2 || ++of->n_rec > file->n_rec)) { \ goto corrupt; \ } \ b##N = row_merge_read_rec(&block[N], &buf[N], \ @@ -1336,14 +1367,14 @@ func_exit: } while (0) /*************************************************************//** -Merge two blocks of linked lists on disk and write a bigger block. +Merge two blocks of records on disk and write a bigger block. @return DB_SUCCESS or error code */ static ulint row_merge_blocks( /*=============*/ const dict_index_t* index, /*!< in: index being created */ - merge_file_t* file, /*!< in/out: file containing + const merge_file_t* file, /*!< in: file containing index entries */ row_merge_block_t* block, /*!< in/out: 3 buffers */ ulint* foffs0, /*!< in/out: offset of first @@ -1366,6 +1397,17 @@ row_merge_blocks( ulint* offsets0;/* offsets of mrec0 */ ulint* offsets1;/* offsets of mrec1 */ +#ifdef UNIV_DEBUG + if (row_merge_print_block) { + fprintf(stderr, + "row_merge_blocks fd=%d ofs=%lu + fd=%d ofs=%lu" + " = fd=%d ofs=%lu\n", + file->fd, (ulong) *foffs0, + file->fd, (ulong) *foffs1, + of->fd, (ulong) of->offset); + } +#endif /* UNIV_DEBUG */ + heap = row_merge_heap_create(index, &offsets0, &offsets1); /* Write a record and read the next record. Split the output @@ -1438,16 +1480,87 @@ done1: } /*************************************************************//** +Copy a block of index entries. +@return TRUE on success, FALSE on failure */ +static __attribute__((nonnull)) +ibool +row_merge_blocks_copy( +/*==================*/ + const dict_index_t* index, /*!< in: index being created */ + const merge_file_t* file, /*!< in: input file */ + row_merge_block_t* block, /*!< in/out: 3 buffers */ + ulint* foffs0, /*!< in/out: input file offset */ + merge_file_t* of) /*!< in/out: output file */ +{ + mem_heap_t* heap; /*!< memory heap for offsets0, offsets1 */ + + mrec_buf_t buf[3]; /*!< buffer for handling + split mrec in block[] */ + const byte* b0; /*!< pointer to block[0] */ + byte* b2; /*!< pointer to block[2] */ + const mrec_t* mrec0; /*!< merge rec, points to block[0] */ + ulint* offsets0;/* offsets of mrec0 */ + ulint* offsets1;/* dummy offsets */ + +#ifdef UNIV_DEBUG + if (row_merge_print_block) { + fprintf(stderr, + "row_merge_blocks_copy fd=%d ofs=%lu" + " = fd=%d ofs=%lu\n", + file->fd, (ulong) foffs0, + of->fd, (ulong) of->offset); + } +#endif /* UNIV_DEBUG */ + + heap = row_merge_heap_create(index, &offsets0, &offsets1); + + /* Write a record and read the next record. Split the output + file in two halves, which can be merged on the following pass. */ + + if (!row_merge_read(file->fd, *foffs0, &block[0])) { +corrupt: + mem_heap_free(heap); + return(FALSE); + } + + b0 = block[0]; + b2 = block[2]; + + b0 = row_merge_read_rec(&block[0], &buf[0], b0, index, file->fd, + foffs0, &mrec0, offsets0); + if (UNIV_UNLIKELY(!b0 && mrec0)) { + + goto corrupt; + } + + if (mrec0) { + /* append all mrec0 to output */ + for (;;) { + ROW_MERGE_WRITE_GET_NEXT(0, goto done0); + } + } +done0: + + /* The file offset points to the beginning of the last page + that has been read. Update it to point to the next block. */ + (*foffs0)++; + + mem_heap_free(heap); + return(row_merge_write_eof(&block[2], b2, of->fd, &of->offset) + != NULL); +} + +/*************************************************************//** Merge disk files. @return DB_SUCCESS or error code */ -static +static __attribute__((nonnull)) ulint row_merge( /*======*/ const dict_index_t* index, /*!< in: index being created */ merge_file_t* file, /*!< in/out: file containing index entries */ - ulint half, /*!< in: half the file */ + ulint* half, /*!< in/out: half the file */ row_merge_block_t* block, /*!< in/out: 3 buffers */ int* tmpfd, /*!< in/out: temporary file handle */ TABLE* table) /*!< in/out: MySQL table, for @@ -1458,43 +1571,75 @@ row_merge( ulint foffs1; /*!< second input offset */ ulint error; /*!< error code */ merge_file_t of; /*!< output file */ + const ulint ihalf = *half; + /*!< half the input file */ + ulint ohalf; /*!< half the output file */ UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]); - ut_ad(half > 0); + ut_ad(ihalf < file->offset); of.fd = *tmpfd; of.offset = 0; + of.n_rec = 0; /* Merge blocks to the output file. */ + ohalf = 0; foffs0 = 0; - foffs1 = half; + foffs1 = ihalf; + + for (; foffs0 < ihalf && foffs1 < file->offset; foffs0++, foffs1++) { + ulint ahalf; /*!< arithmetic half the input file */ - for (; foffs0 < half && foffs1 < file->offset; foffs0++, foffs1++) { error = row_merge_blocks(index, file, block, &foffs0, &foffs1, &of, table); if (error != DB_SUCCESS) { return(error); } + + /* Record the offset of the output file when + approximately half the output has been generated. In + this way, the next invocation of row_merge() will + spend most of the time in this loop. The initial + estimate is ohalf==0. */ + ahalf = file->offset / 2; + ut_ad(ohalf <= of.offset); + + /* Improve the estimate until reaching half the input + file size, or we can not get any closer to it. All + comparands should be non-negative when !(ohalf < ahalf) + because ohalf <= of.offset. */ + if (ohalf < ahalf || of.offset - ahalf < ohalf - ahalf) { + ohalf = of.offset; + } } - /* Copy the last block, if there is one. */ - while (foffs0 < half) { - if (!row_merge_read(file->fd, foffs0++, block) - || !row_merge_write(of.fd, of.offset++, block)) { + /* Copy the last blocks, if there are any. */ + + while (foffs0 < ihalf) { + if (!row_merge_blocks_copy(index, file, block, &foffs0, &of)) { return(DB_CORRUPTION); } } + + ut_ad(foffs0 == ihalf); + while (foffs1 < file->offset) { - if (!row_merge_read(file->fd, foffs1++, block) - || !row_merge_write(of.fd, of.offset++, block)) { + if (!row_merge_blocks_copy(index, file, block, &foffs1, &of)) { return(DB_CORRUPTION); } } + ut_ad(foffs1 == file->offset); + + if (UNIV_UNLIKELY(of.n_rec != file->n_rec)) { + return(DB_CORRUPTION); + } + /* Swap file descriptors for the next pass. */ *tmpfd = file->fd; *file = of; + *half = ohalf; UNIV_MEM_INVALID(block[0], 3 * sizeof block[0]); @@ -1517,20 +1662,25 @@ row_merge_sort( reporting erroneous key value if applicable */ { - ulint blksz; /*!< block size */ + ulint half = file->offset / 2; + + /* The file should always contain at least one byte (the end + of file marker). Thus, it must be at least one block. */ + ut_ad(file->offset > 0); - for (blksz = 1; blksz < file->offset; blksz *= 2) { - ulint half; + do { ulint error; - ut_ad(ut_is_2pow(blksz)); - half = ut_2pow_round((file->offset + (blksz - 1)) / 2, blksz); - error = row_merge(index, file, half, block, tmpfd, table); + error = row_merge(index, file, &half, block, tmpfd, table); if (error != DB_SUCCESS) { return(error); } - } + + /* half > 0 should hold except when the file consists + of one block. No need to merge further then. */ + ut_ad(half > 0 || file->offset == 1); + } while (half < file->offset && half > 0); return(DB_SUCCESS); } @@ -1797,7 +1947,15 @@ row_merge_drop_index( static const char str1[] = "PROCEDURE DROP_INDEX_PROC () IS\n" "BEGIN\n" + /* Rename the index, so that it will be dropped by + row_merge_drop_temp_indexes() at crash recovery + if the server crashes before this trx is committed. */ + "UPDATE SYS_INDEXES SET NAME=CONCAT('" + TEMP_INDEX_PREFIX_STR "', NAME) WHERE ID = :indexid;\n" + "COMMIT WORK;\n" + /* Drop the field definitions of the index. */ "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n" + /* Drop the index definition and the B-tree. */ "DELETE FROM SYS_INDEXES WHERE ID = :indexid\n" " AND TABLE_ID = :tableid;\n" "END;\n"; @@ -1909,6 +2067,7 @@ row_merge_file_create( { merge_file->fd = innobase_mysql_tmpfile(); merge_file->offset = 0; + merge_file->n_rec = 0; } /*********************************************************************//** @@ -2129,7 +2288,7 @@ row_merge_rename_tables( if (err != DB_SUCCESS) { err_exit: trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; } diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index b345bb59624..540a4450045 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -510,7 +510,7 @@ handle_new_error: switch (err) { case DB_LOCK_WAIT_TIMEOUT: if (row_rollback_on_timeout) { - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); break; } /* fall through */ @@ -526,7 +526,7 @@ handle_new_error: /* Roll back the latest, possibly incomplete insertion or update */ - trx_general_rollback_for_mysql(trx, TRUE, savept); + trx_general_rollback_for_mysql(trx, savept); } /* MySQL will roll back the latest SQL statement */ break; @@ -548,7 +548,7 @@ handle_new_error: /* Roll back the whole transaction; this resolution was added to version 3.23.43 */ - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); break; case DB_MUST_GET_MORE_FILE_SPACE: @@ -866,18 +866,22 @@ row_update_statistics_if_needed( } /*********************************************************************//** -Unlocks AUTO_INC type locks that were possibly reserved by a trx. */ +Unlocks AUTO_INC type locks that were possibly reserved by a trx. This +function should be called at the the end of an SQL statement, by the +connection thread that owns the transaction (trx->mysql_thd). */ UNIV_INTERN void row_unlock_table_autoinc_for_mysql( /*===============================*/ trx_t* trx) /*!< in/out: transaction */ { - mutex_enter(&kernel_mutex); + if (lock_trx_holds_autoinc_locks(trx)) { + mutex_enter(&kernel_mutex); - lock_release_autoinc_locks(trx); + lock_release_autoinc_locks(trx); - mutex_exit(&kernel_mutex); + mutex_exit(&kernel_mutex); + } } /*********************************************************************//** @@ -1767,7 +1771,6 @@ row_create_table_for_mysql( const char* table_name; ulint table_name_len; ulint err; - ulint i; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); #ifdef UNIV_SYNC_DEBUG @@ -1802,15 +1805,6 @@ err_exit: goto err_exit; } - /* Check that no reserved column names are used. */ - for (i = 0; i < dict_table_get_n_user_cols(table); i++) { - if (dict_col_name_is_reserved( - dict_table_get_col_name(table, i))) { - - goto err_exit; - } - } - trx_start_if_not_started(trx); /* The table name is prefixed with the database name and a '/'. @@ -1885,7 +1879,7 @@ err_exit: if (UNIV_UNLIKELY(err != DB_SUCCESS)) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); } switch (err) { @@ -2053,7 +2047,7 @@ error_handling: trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); row_drop_table_for_mysql(table_name, trx, FALSE); @@ -2074,7 +2068,7 @@ Scans a table create SQL string and adds to the data dictionary the foreign key constraints declared in the string. This function should be called after the indexes for a table have been created. Each foreign key constraint must be accompanied with indexes in -bot participating tables. The indexes are allowed to contain more +both participating tables. The indexes are allowed to contain more fields than mentioned in the constraint. Check also that foreign key constraints which reference this table are ok. @return error code or DB_SUCCESS */ @@ -2121,7 +2115,7 @@ row_table_add_foreign_constraints( trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); row_drop_table_for_mysql(name, trx, FALSE); @@ -2488,7 +2482,7 @@ row_discard_tablespace_for_mysql( if (err != DB_SUCCESS) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; } else { dict_table_change_id_in_cache(table, new_id); @@ -2497,7 +2491,7 @@ row_discard_tablespace_for_mysql( if (!success) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; err = DB_ERROR; @@ -2949,7 +2943,7 @@ next_rec: if (err != DB_SUCCESS) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; ut_print_timestamp(stderr); fputs(" InnoDB: Unable to assign a new identifier to table ", @@ -3590,7 +3584,7 @@ row_delete_constraint( if ((err == DB_SUCCESS) && !strchr(id, '/')) { /* Old format < 4.0.18 constraints have constraint ids - <number>_<number>. We only try deleting them if the + NUMBER_NUMBER. We only try deleting them if the constraint name does not contain a '/' character, otherwise deleting a new format constraint named 'foo/bar' from database 'baz' would remove constraint 'bar' from database @@ -3854,7 +3848,7 @@ end: "InnoDB: succeed.\n", stderr); } trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; } else { /* The following call will also rename the .ibd data file if @@ -3863,7 +3857,7 @@ end: if (!dict_table_rename_in_cache(table, new_name, !new_is_tmp)) { trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; goto funct_exit; } @@ -3903,7 +3897,7 @@ end: ut_a(dict_table_rename_in_cache(table, old_name, FALSE)); trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, NULL); + trx_general_rollback_for_mysql(trx, NULL); trx->error_state = DB_SUCCESS; } } diff --git a/storage/innodb_plugin/scripts/export.sh b/storage/innodb_plugin/scripts/export.sh new file mode 100755 index 00000000000..2a4355c1e43 --- /dev/null +++ b/storage/innodb_plugin/scripts/export.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# +# export current working directory in a format suitable for sending to MySQL +# as a snapshot. also generates the actual snapshot and sends it to MySQL. + +set -eu + +die () { + echo $* + exit 1 +} + +if [ $# -ne 2 ] ; then + die "Usage: export.sh revision-number-of-last-snapshot current-revision-number" +fi + +# If we are run from within the scripts/ directory then change directory to +# one level up so that the relative paths work. +DIR=`basename $PWD` + +if [ "${DIR}" = "scripts" ]; then + cd .. +fi + +START_REV=$(($1 + 1)) +END_REV=$2 + +set +u +if test -z $EDITOR; then + die "\$EDITOR is not set" +fi +set -u + +rm -rf to-mysql +mkdir to-mysql{,/storage,/patches,/mysql-test{,/t,/r,/include}} +svn log -v -r "$START_REV:BASE" > to-mysql/log +svn export -q . to-mysql/storage/innobase + +REV=$START_REV +while [ $REV -le $END_REV ] +do + PATCH=to-mysql/patches/r$REV.patch + svn log -v -r$REV > $PATCH + if [ $(wc -c < $PATCH) -gt 73 ] + then + svn diff -r$(($REV-1)):$REV >> $PATCH + else + rm $PATCH + fi + REV=$(($REV + 1)) +done + +cd to-mysql/storage/innobase + +mv mysql-test/*.test mysql-test/*.opt ../../mysql-test/t +mv mysql-test/*.result ../../mysql-test/r +mv mysql-test/*.inc ../../mysql-test/include +rmdir mysql-test + +rm setup.sh export.sh revert_gen.sh compile-innodb-debug compile-innodb + +cd ../.. +$EDITOR log +cd .. + +fname="innodb-5.1-ss$2.tar.gz" + +rm -f $fname +tar czf $fname to-mysql +scp $fname mysql:snapshots +rm $fname +rm -rf to-mysql + +echo "Sent $fname to MySQL" diff --git a/storage/innodb_plugin/srv/srv0srv.c b/storage/innodb_plugin/srv/srv0srv.c index 79fa08e7cdf..d638b23692e 100644 --- a/storage/innodb_plugin/srv/srv0srv.c +++ b/storage/innodb_plugin/srv/srv0srv.c @@ -102,6 +102,7 @@ Created 10/8/1995 Heikki Tuuri #include "row0mysql.h" #include "ha_prototypes.h" #include "trx0i_s.h" +#include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ /* This is set to TRUE if the MySQL user has set it in MySQL; currently affects only FOREIGN KEY definition parsing */ @@ -292,12 +293,6 @@ UNIV_INTERN ulint srv_buf_pool_flushed = 0; reading of a disk page */ UNIV_INTERN ulint srv_buf_pool_reads = 0; -/** Number of sequential read-aheads */ -UNIV_INTERN ulint srv_read_ahead_seq = 0; - -/** Number of random read-aheads */ -UNIV_INTERN ulint srv_read_ahead_rnd = 0; - /* structure to pass status variables to MySQL */ UNIV_INTERN export_struc export_vars; @@ -464,8 +459,6 @@ static ulint srv_main_background_loops = 0; static ulint srv_main_flush_loops = 0; /* Log writes involving flush. */ static ulint srv_log_writes_and_flush = 0; -/* Log writes not including flush. */ -static ulint srv_log_buffer_writes = 0; /* This is only ever touched by the master thread. It records the time when the last flush of log file has happened. The master @@ -614,7 +607,7 @@ future, but at the moment we plan to implement a more coarse solution, which could be called a global priority inheritance. If a thread has to wait for a long time, say 300 milliseconds, for a resource, we just guess that it may be waiting for a resource owned by a background -thread, and boost the the priority of all runnable background threads +thread, and boost the priority of all runnable background threads to the normal level. The background threads then themselves adjust their fixed priority back to background after releasing all resources they had (or, at some fixed points in their program code). @@ -714,9 +707,8 @@ srv_print_master_thread_info( srv_main_1_second_loops, srv_main_sleeps, srv_main_10_second_loops, srv_main_background_loops, srv_main_flush_loops); - fprintf(file, "srv_master_thread log flush and writes: %lu " - " log writes only: %lu\n", - srv_log_writes_and_flush, srv_log_buffer_writes); + fprintf(file, "srv_master_thread log flush and writes: %lu\n", + srv_log_writes_and_flush); } /*********************************************************************//** @@ -1877,14 +1869,16 @@ srv_export_innodb_status(void) export_vars.innodb_data_reads = os_n_file_reads; export_vars.innodb_data_writes = os_n_file_writes; export_vars.innodb_data_written = srv_data_written; - export_vars.innodb_buffer_pool_read_requests = buf_pool->n_page_gets; + export_vars.innodb_buffer_pool_read_requests = buf_pool->stat.n_page_gets; export_vars.innodb_buffer_pool_write_requests = srv_buf_pool_write_requests; export_vars.innodb_buffer_pool_wait_free = srv_buf_pool_wait_free; export_vars.innodb_buffer_pool_pages_flushed = srv_buf_pool_flushed; export_vars.innodb_buffer_pool_reads = srv_buf_pool_reads; - export_vars.innodb_buffer_pool_read_ahead_rnd = srv_read_ahead_rnd; - export_vars.innodb_buffer_pool_read_ahead_seq = srv_read_ahead_seq; + export_vars.innodb_buffer_pool_read_ahead + = buf_pool->stat.n_ra_pages_read; + export_vars.innodb_buffer_pool_read_ahead_evicted + = buf_pool->stat.n_ra_pages_evicted; export_vars.innodb_buffer_pool_pages_data = UT_LIST_GET_LEN(buf_pool->LRU); export_vars.innodb_buffer_pool_pages_dirty @@ -1915,9 +1909,9 @@ srv_export_innodb_status(void) export_vars.innodb_log_writes = srv_log_writes; export_vars.innodb_dblwr_pages_written = srv_dblwr_pages_written; export_vars.innodb_dblwr_writes = srv_dblwr_writes; - export_vars.innodb_pages_created = buf_pool->n_pages_created; - export_vars.innodb_pages_read = buf_pool->n_pages_read; - export_vars.innodb_pages_written = buf_pool->n_pages_written; + export_vars.innodb_pages_created = buf_pool->stat.n_pages_created; + export_vars.innodb_pages_read = buf_pool->stat.n_pages_read; + export_vars.innodb_pages_written = buf_pool->stat.n_pages_written; export_vars.innodb_row_lock_waits = srv_n_lock_wait_count; export_vars.innodb_row_lock_current_waits = srv_n_lock_wait_current_count; @@ -2284,12 +2278,6 @@ srv_sync_log_buffer_in_background(void) log_buffer_sync_in_background(TRUE); srv_last_log_flush_time = current_time; srv_log_writes_and_flush++; - } else { - /* Actually we don't need to write logs here. - We are just being extra safe here by forcing - the log buffer to log file. */ - log_buffer_sync_in_background(FALSE); - srv_log_buffer_writes++; } } @@ -2340,8 +2328,8 @@ loop: srv_main_thread_op_info = "reserving kernel mutex"; - n_ios_very_old = log_sys->n_log_ios + buf_pool->n_pages_read - + buf_pool->n_pages_written; + n_ios_very_old = log_sys->n_log_ios + buf_pool->stat.n_pages_read + + buf_pool->stat.n_pages_written; mutex_enter(&kernel_mutex); /* Store the user activity counter at the start of this loop */ @@ -2361,8 +2349,8 @@ loop: skip_sleep = FALSE; for (i = 0; i < 10; i++) { - n_ios_old = log_sys->n_log_ios + buf_pool->n_pages_read - + buf_pool->n_pages_written; + n_ios_old = log_sys->n_log_ios + buf_pool->stat.n_pages_read + + buf_pool->stat.n_pages_written; srv_main_thread_op_info = "sleeping"; srv_main_1_second_loops++; @@ -2401,8 +2389,8 @@ loop: n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes; - n_ios = log_sys->n_log_ios + buf_pool->n_pages_read - + buf_pool->n_pages_written; + n_ios = log_sys->n_log_ios + buf_pool->stat.n_pages_read + + buf_pool->stat.n_pages_written; if (n_pend_ios < SRV_PEND_IO_THRESHOLD && (n_ios - n_ios_old < SRV_RECENT_IO_ACTIVITY)) { srv_main_thread_op_info = "doing insert buffer merge"; @@ -2418,6 +2406,8 @@ loop: /* Try to keep the number of modified pages in the buffer pool under the limit wished by the user */ + srv_main_thread_op_info = + "flushing buffer pool pages"; n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, PCT_IO(100), IB_ULONGLONG_MAX); @@ -2436,6 +2426,8 @@ loop: ulint n_flush = buf_flush_get_desired_flush_rate(); if (n_flush) { + srv_main_thread_op_info = + "flushing buffer pool pages"; n_flush = ut_min(PCT_IO(100), n_flush); n_pages_flushed = buf_flush_batch( @@ -2473,8 +2465,8 @@ loop: are not required, and may be disabled. */ n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes; - n_ios = log_sys->n_log_ios + buf_pool->n_pages_read - + buf_pool->n_pages_written; + n_ios = log_sys->n_log_ios + buf_pool->stat.n_pages_read + + buf_pool->stat.n_pages_written; srv_main_10_second_loops++; if (n_pend_ios < SRV_PEND_IO_THRESHOLD diff --git a/storage/innodb_plugin/srv/srv0start.c b/storage/innodb_plugin/srv/srv0start.c index a942fd439a3..796541a9f1a 100644 --- a/storage/innodb_plugin/srv/srv0start.c +++ b/storage/innodb_plugin/srv/srv0start.c @@ -103,6 +103,7 @@ Created 2/16/1996 Heikki Tuuri # include "row0row.h" # include "row0mysql.h" # include "btr0pcur.h" +# include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ /** Log sequence number immediately after startup */ UNIV_INTERN ib_uint64_t srv_start_lsn; @@ -1096,6 +1097,10 @@ innobase_start_or_create_for_mysql(void) "InnoDB: !!!!!!!! UNIV_SEARCH_DEBUG switched on !!!!!!!!!\n"); #endif +#ifdef UNIV_LOG_LSN_DEBUG + fprintf(stderr, + "InnoDB: !!!!!!!! UNIV_LOG_LSN_DEBUG switched on !!!!!!!!!\n"); +#endif /* UNIV_LOG_LSN_DEBUG */ #ifdef UNIV_MEM_DEBUG fprintf(stderr, "InnoDB: !!!!!!!! UNIV_MEM_DEBUG switched on !!!!!!!!!\n"); @@ -1106,34 +1111,7 @@ innobase_start_or_create_for_mysql(void) "InnoDB: The InnoDB memory heap is disabled\n"); } -#ifdef HAVE_GCC_ATOMIC_BUILTINS -# ifdef INNODB_RW_LOCKS_USE_ATOMICS - fprintf(stderr, - "InnoDB: Mutexes and rw_locks use GCC atomic builtins.\n"); -# else /* INNODB_RW_LOCKS_USE_ATOMICS */ - fprintf(stderr, - "InnoDB: Mutexes use GCC atomic builtins, rw_locks do not.\n"); -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ -#elif defined(HAVE_SOLARIS_ATOMICS) -# ifdef INNODB_RW_LOCKS_USE_ATOMICS - fprintf(stderr, - "InnoDB: Mutexes and rw_locks use Solaris atomic functions.\n"); -# else - fprintf(stderr, - "InnoDB: Mutexes use Solaris atomic functions.\n"); -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ -#elif HAVE_WINDOWS_ATOMICS -# ifdef INNODB_RW_LOCKS_USE_ATOMICS - fprintf(stderr, - "InnoDB: Mutexes and rw_locks use Windows interlocked functions.\n"); -# else - fprintf(stderr, - "InnoDB: Mutexes use Windows interlocked functions.\n"); -# endif /* INNODB_RW_LOCKS_USE_ATOMICS */ -#else /* HAVE_GCC_ATOMIC_BUILTINS */ - fprintf(stderr, - "InnoDB: Neither mutexes nor rw_locks use GCC atomic builtins.\n"); -#endif /* HAVE_GCC_ATOMIC_BUILTINS */ + fprintf(stderr, "InnoDB: %s\n", IB_ATOMICS_STARTUP_MSG); /* Since InnoDB does not currently clean up all its internal data structures in MySQL Embedded Server Library server_end(), we @@ -1398,7 +1376,7 @@ innobase_start_or_create_for_mysql(void) sum_of_new_sizes += srv_data_file_sizes[i]; } - if (sum_of_new_sizes < 640) { + if (sum_of_new_sizes < 10485760 / UNIV_PAGE_SIZE) { fprintf(stderr, "InnoDB: Error: tablespace size must be" " at least 10 MB\n"); @@ -1829,7 +1807,7 @@ innobase_start_or_create_for_mysql(void) /* Actually, we did not change the undo log format between 4.0 and 4.1.1, and we would not need to run purge to completion. Note also that the purge algorithm in 4.1.1 - can process the the history list again even after a full + can process the history list again even after a full purge, because our algorithm does not cut the end of the history list in all cases so that it would become empty after a full purge. That mean that we may purge 4.0 type diff --git a/storage/innodb_plugin/sync/sync0rw.c b/storage/innodb_plugin/sync/sync0rw.c index 0ed114e330c..d231b6acdf7 100644 --- a/storage/innodb_plugin/sync/sync0rw.c +++ b/storage/innodb_plugin/sync/sync0rw.c @@ -38,6 +38,7 @@ Created 9/11/1995 Heikki Tuuri #include "os0thread.h" #include "mem0mem.h" #include "srv0srv.h" +#include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ /* IMPLEMENTATION OF THE RW_LOCK diff --git a/storage/innodb_plugin/sync/sync0sync.c b/storage/innodb_plugin/sync/sync0sync.c index 84ed08e14e7..5ad143075a7 100644 --- a/storage/innodb_plugin/sync/sync0sync.c +++ b/storage/innodb_plugin/sync/sync0sync.c @@ -39,6 +39,7 @@ Created 9/5/1995 Heikki Tuuri #include "buf0buf.h" #include "srv0srv.h" #include "buf0types.h" +#include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ /* REASONS FOR IMPLEMENTING THE SPIN LOCK MUTEX @@ -849,7 +850,8 @@ sync_thread_levels_g( /*=================*/ sync_level_t* arr, /*!< in: pointer to level array for an OS thread */ - ulint limit) /*!< in: level limit */ + ulint limit, /*!< in: level limit */ + ulint warn) /*!< in: TRUE=display a diagnostic message */ { sync_level_t* slot; rw_lock_t* lock; @@ -863,6 +865,11 @@ sync_thread_levels_g( if (slot->latch != NULL) { if (slot->level <= limit) { + if (!warn) { + + return(FALSE); + } + lock = slot->latch; mutex = slot->latch; @@ -1100,7 +1107,7 @@ sync_thread_add_level( case SYNC_DICT_HEADER: case SYNC_TRX_I_S_RWLOCK: case SYNC_TRX_I_S_LAST_READ: - if (!sync_thread_levels_g(array, level)) { + if (!sync_thread_levels_g(array, level, TRUE)) { fprintf(stderr, "InnoDB: sync_thread_levels_g(array, %lu)" " does not hold!\n", level); @@ -1111,36 +1118,44 @@ sync_thread_add_level( /* Either the thread must own the buffer pool mutex (buf_pool_mutex), or it is allowed to latch only ONE buffer block (block->mutex or buf_pool_zip_mutex). */ - if (!sync_thread_levels_g(array, level)) { - ut_a(sync_thread_levels_g(array, level - 1)); + if (!sync_thread_levels_g(array, level, FALSE)) { + ut_a(sync_thread_levels_g(array, level - 1, TRUE)); ut_a(sync_thread_levels_contain(array, SYNC_BUF_POOL)); } break; case SYNC_REC_LOCK: - ut_a((sync_thread_levels_contain(array, SYNC_KERNEL) - && sync_thread_levels_g(array, SYNC_REC_LOCK - 1)) - || sync_thread_levels_g(array, SYNC_REC_LOCK)); + if (sync_thread_levels_contain(array, SYNC_KERNEL)) { + ut_a(sync_thread_levels_g(array, SYNC_REC_LOCK - 1, + TRUE)); + } else { + ut_a(sync_thread_levels_g(array, SYNC_REC_LOCK, TRUE)); + } break; case SYNC_IBUF_BITMAP: /* Either the thread must own the master mutex to all the bitmap pages, or it is allowed to latch only ONE bitmap page. */ - ut_a((sync_thread_levels_contain(array, SYNC_IBUF_BITMAP_MUTEX) - && sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1)) - || sync_thread_levels_g(array, SYNC_IBUF_BITMAP)); + if (sync_thread_levels_contain(array, + SYNC_IBUF_BITMAP_MUTEX)) { + ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1, + TRUE)); + } else { + ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP, + TRUE)); + } break; case SYNC_FSP_PAGE: ut_a(sync_thread_levels_contain(array, SYNC_FSP)); break; case SYNC_FSP: ut_a(sync_thread_levels_contain(array, SYNC_FSP) - || sync_thread_levels_g(array, SYNC_FSP)); + || sync_thread_levels_g(array, SYNC_FSP, TRUE)); break; case SYNC_TRX_UNDO_PAGE: ut_a(sync_thread_levels_contain(array, SYNC_TRX_UNDO) || sync_thread_levels_contain(array, SYNC_RSEG) || sync_thread_levels_contain(array, SYNC_PURGE_SYS) - || sync_thread_levels_g(array, SYNC_TRX_UNDO_PAGE)); + || sync_thread_levels_g(array, SYNC_TRX_UNDO_PAGE, TRUE)); break; case SYNC_RSEG_HEADER: ut_a(sync_thread_levels_contain(array, SYNC_RSEG)); @@ -1152,37 +1167,41 @@ sync_thread_add_level( case SYNC_TREE_NODE: ut_a(sync_thread_levels_contain(array, SYNC_INDEX_TREE) || sync_thread_levels_contain(array, SYNC_DICT_OPERATION) - || sync_thread_levels_g(array, SYNC_TREE_NODE - 1)); + || sync_thread_levels_g(array, SYNC_TREE_NODE - 1, TRUE)); break; case SYNC_TREE_NODE_NEW: ut_a(sync_thread_levels_contain(array, SYNC_FSP_PAGE) || sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); break; case SYNC_INDEX_TREE: - ut_a((sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) - && sync_thread_levels_contain(array, SYNC_FSP) - && sync_thread_levels_g(array, SYNC_FSP_PAGE - 1)) - || sync_thread_levels_g(array, SYNC_TREE_NODE - 1)); + if (sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) + && sync_thread_levels_contain(array, SYNC_FSP)) { + ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, + TRUE)); + } else { + ut_a(sync_thread_levels_g(array, SYNC_TREE_NODE - 1, + TRUE)); + } break; case SYNC_IBUF_MUTEX: - ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1)); + ut_a(sync_thread_levels_g(array, SYNC_FSP_PAGE - 1, TRUE)); break; case SYNC_IBUF_PESS_INSERT_MUTEX: - ut_a(sync_thread_levels_g(array, SYNC_FSP - 1) - && !sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE)); + ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); break; case SYNC_IBUF_HEADER: - ut_a(sync_thread_levels_g(array, SYNC_FSP - 1) - && !sync_thread_levels_contain(array, SYNC_IBUF_MUTEX) - && !sync_thread_levels_contain( - array, SYNC_IBUF_PESS_INSERT_MUTEX)); + ut_a(sync_thread_levels_g(array, SYNC_FSP - 1, TRUE)); + ut_a(!sync_thread_levels_contain(array, SYNC_IBUF_MUTEX)); + ut_a(!sync_thread_levels_contain(array, + SYNC_IBUF_PESS_INSERT_MUTEX)); break; case SYNC_DICT: #ifdef UNIV_DEBUG ut_a(buf_debug_prints - || sync_thread_levels_g(array, SYNC_DICT)); + || sync_thread_levels_g(array, SYNC_DICT, TRUE)); #else /* UNIV_DEBUG */ - ut_a(sync_thread_levels_g(array, SYNC_DICT)); + ut_a(sync_thread_levels_g(array, SYNC_DICT, TRUE)); #endif /* UNIV_DEBUG */ break; default: diff --git a/storage/innodb_plugin/thr/thr0loc.c b/storage/innodb_plugin/thr/thr0loc.c index 18f7b0707bd..49275be1d7d 100644 --- a/storage/innodb_plugin/thr/thr0loc.c +++ b/storage/innodb_plugin/thr/thr0loc.c @@ -62,7 +62,7 @@ struct thr_local_struct{ os_thread_t handle; /*!< operating system handle to the thread */ ulint slot_no;/*!< the index of the slot in the thread table for this thread */ - ibool in_ibuf;/*!< TRUE if the the thread is doing an ibuf + ibool in_ibuf;/*!< TRUE if the thread is doing an ibuf operation */ hash_node_t hash; /*!< hash chain node */ ulint magic_n;/*!< magic number (THR_LOCAL_MAGIC_N) */ diff --git a/storage/innodb_plugin/trx/trx0rec.c b/storage/innodb_plugin/trx/trx0rec.c index 36911c9df85..5097cf18dcd 100644 --- a/storage/innodb_plugin/trx/trx0rec.c +++ b/storage/innodb_plugin/trx/trx0rec.c @@ -1333,7 +1333,7 @@ trx_undo_get_undo_rec_low( ulint rseg_id; ulint page_no; ulint offset; - page_t* undo_page; + const page_t* undo_page; trx_rseg_t* rseg; ibool is_insert; mtr_t mtr; @@ -1572,7 +1572,7 @@ trx_undo_prev_version_build( /* We have to set the appropriate extern storage bits in the old version of the record: the extern bits in rec for those - fields that update does NOT update, as well as the the bits for + fields that update does NOT update, as well as the bits for those fields that update updates to become externally stored fields. Store the info: */ diff --git a/storage/innodb_plugin/trx/trx0roll.c b/storage/innodb_plugin/trx/trx0roll.c index 51d17192d5b..c925478cdf4 100644 --- a/storage/innodb_plugin/trx/trx0roll.c +++ b/storage/innodb_plugin/trx/trx0roll.c @@ -66,9 +66,9 @@ int trx_general_rollback_for_mysql( /*===========================*/ trx_t* trx, /*!< in: transaction handle */ - ibool partial,/*!< in: TRUE if partial rollback requested */ trx_savept_t* savept) /*!< in: pointer to savepoint undo number, if - partial rollback requested */ + partial rollback requested, or NULL for + complete rollback */ { mem_heap_t* heap; que_thr_t* thr; @@ -85,9 +85,8 @@ trx_general_rollback_for_mysql( roll_node = roll_node_create(heap); - roll_node->partial = partial; - - if (partial) { + if (savept) { + roll_node->partial = TRUE; roll_node->savept = *savept; } @@ -145,7 +144,7 @@ trx_rollback_for_mysql( the transaction object does not have an InnoDB session object, and we set a dummy session that we use for all MySQL transactions. */ - err = trx_general_rollback_for_mysql(trx, FALSE, NULL); + err = trx_general_rollback_for_mysql(trx, NULL); trx->op_info = ""; @@ -170,8 +169,7 @@ trx_rollback_last_sql_stat_for_mysql( trx->op_info = "rollback of SQL statement"; - err = trx_general_rollback_for_mysql(trx, TRUE, - &(trx->last_sql_stat_start)); + err = trx_general_rollback_for_mysql(trx, &trx->last_sql_stat_start); /* The following call should not be needed, but we play safe: */ trx_mark_sql_stat_end(trx); @@ -282,7 +280,7 @@ trx_rollback_to_savepoint_for_mysql( trx->op_info = "rollback to a savepoint"; - err = trx_general_rollback_for_mysql(trx, TRUE, &(savep->savept)); + err = trx_general_rollback_for_mysql(trx, &savep->savept); /* Store the current undo_no of the transaction so that we know where to roll back if we have to roll back the next SQL statement: */ @@ -534,28 +532,26 @@ trx_rollback_active( Rollback or clean up any incomplete transactions which were encountered in crash recovery. If the transaction already was committed, then we clean up a possible insert undo log. If the -transaction was not yet committed, then we roll it back. -Note: this is done in a background thread. -@return a dummy parameter */ +transaction was not yet committed, then we roll it back. */ UNIV_INTERN -os_thread_ret_t -trx_rollback_or_clean_all_recovered( -/*================================*/ - void* arg __attribute__((unused))) - /*!< in: a dummy parameter required by - os_thread_create */ +void +trx_rollback_or_clean_recovered( +/*============================*/ + ibool all) /*!< in: FALSE=roll back dictionary transactions; + TRUE=roll back all non-PREPARED transactions */ { trx_t* trx; mutex_enter(&kernel_mutex); - if (UT_LIST_GET_FIRST(trx_sys->trx_list)) { + if (!UT_LIST_GET_FIRST(trx_sys->trx_list)) { + goto leave_function; + } + if (all) { fprintf(stderr, "InnoDB: Starting in background the rollback" " of uncommitted transactions\n"); - } else { - goto leave_function; } mutex_exit(&kernel_mutex); @@ -584,18 +580,42 @@ loop: goto loop; case TRX_ACTIVE: - mutex_exit(&kernel_mutex); - trx_rollback_active(trx); - goto loop; + if (all || trx_get_dict_operation(trx) + != TRX_DICT_OP_NONE) { + mutex_exit(&kernel_mutex); + trx_rollback_active(trx); + goto loop; + } } } - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Rollback of non-prepared transactions completed\n"); + if (all) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Rollback of non-prepared" + " transactions completed\n"); + } leave_function: mutex_exit(&kernel_mutex); +} + +/*******************************************************************//** +Rollback or clean up any incomplete transactions which were +encountered in crash recovery. If the transaction already was +committed, then we clean up a possible insert undo log. If the +transaction was not yet committed, then we roll it back. +Note: this is done in a background thread. +@return a dummy parameter */ +UNIV_INTERN +os_thread_ret_t +trx_rollback_or_clean_all_recovered( +/*================================*/ + void* arg __attribute__((unused))) + /*!< in: a dummy parameter required by + os_thread_create */ +{ + trx_rollback_or_clean_recovered(TRUE); /* We count the number of threads in os_thread_exit(). A created thread should always use that to exit and not use return() to exit. */ diff --git a/storage/innodb_plugin/trx/trx0trx.c b/storage/innodb_plugin/trx/trx0trx.c index 4d4885062a6..21ba6e481a7 100644 --- a/storage/innodb_plugin/trx/trx0trx.c +++ b/storage/innodb_plugin/trx/trx0trx.c @@ -803,7 +803,7 @@ trx_commit_off_kernel( in exactly the same order as commit lsn's, if the transactions have different rollback segments. To get exactly the same order we should hold the kernel mutex up to this point, - adding to to the contention of the kernel mutex. However, if + adding to the contention of the kernel mutex. However, if a transaction T2 is able to see modifications made by a transaction T1, T2 will always get a bigger transaction number and a bigger commit lsn than T1. */ @@ -950,7 +950,7 @@ trx_commit_off_kernel( /****************************************************************//** Cleans up a transaction at database startup. The cleanup is needed if the transaction already got to the middle of a commit when the database -crashed, andf we cannot roll it back. */ +crashed, and we cannot roll it back. */ UNIV_INTERN void trx_cleanup_at_db_startup( diff --git a/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_solaris.c b/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_solaris.c index a18a537d1d4..310603c7503 100644 --- a/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_solaris.c +++ b/storage/innodb_plugin/ut/ut0auxconf_atomic_pthread_t_solaris.c @@ -17,18 +17,38 @@ Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ /***************************************************************************** -If this program compiles, then pthread_t objects can be used as arguments -to Solaris libc atomic functions. +If this program compiles and returns 0, then pthread_t objects can be used as +arguments to Solaris libc atomic functions. Created April 18, 2009 Vasil Dimov *****************************************************************************/ #include <pthread.h> +#include <string.h> int main(int argc, char** argv) { - pthread_t x = 0; + pthread_t x1; + pthread_t x2; + pthread_t x3; + + memset(&x1, 0x0, sizeof(x1)); + memset(&x2, 0x0, sizeof(x2)); + memset(&x3, 0x0, sizeof(x3)); + + if (sizeof(pthread_t) == 4) { + + atomic_cas_32(&x1, x2, x3); + + } else if (sizeof(pthread_t) == 8) { + + atomic_cas_64(&x1, x2, x3); + + } else { + + return(1); + } return(0); } diff --git a/storage/innodb_plugin/ut/ut0auxconf_have_gcc_atomics.c b/storage/innodb_plugin/ut/ut0auxconf_have_gcc_atomics.c new file mode 100644 index 00000000000..da5c13d7d79 --- /dev/null +++ b/storage/innodb_plugin/ut/ut0auxconf_have_gcc_atomics.c @@ -0,0 +1,61 @@ +/***************************************************************************** + +Copyright (c) 2009, Innobase Oy. 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 + +*****************************************************************************/ + +/***************************************************************************** +If this program compiles and returns 0, then GCC atomic funcions are available. + +Created September 12, 2009 Vasil Dimov +*****************************************************************************/ + +int +main(int argc, char** argv) +{ + long x; + long y; + long res; + char c; + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x, y); + if (!res || x != y) { + return(1); + } + + x = 10; + y = 123; + res = __sync_bool_compare_and_swap(&x, x + 1, y); + if (res || x != 10) { + return(1); + } + + x = 10; + y = 123; + res = __sync_add_and_fetch(&x, y); + if (res != 123 + 10 || x != 123 + 10) { + return(1); + } + + c = 10; + res = __sync_lock_test_and_set(&c, 123); + if (res != 10 || c != 123) { + return(1); + } + + return(0); +} diff --git a/storage/innodb_plugin/ut/ut0ut.c b/storage/innodb_plugin/ut/ut0ut.c index e4cc226fbad..498873e290a 100644 --- a/storage/innodb_plugin/ut/ut0ut.c +++ b/storage/innodb_plugin/ut/ut0ut.c @@ -132,6 +132,7 @@ ut_time(void) return(time(NULL)); } +#ifndef UNIV_HOTBACKUP /**********************************************************//** Returns system time. Upon successful completion, the value 0 is returned; otherwise the @@ -200,6 +201,24 @@ ut_time_us( } /**********************************************************//** +Returns the number of milliseconds since some epoch. The +value may wrap around. It should only be used for heuristic +purposes. +@return ms since epoch */ +UNIV_INTERN +ulint +ut_time_ms(void) +/*============*/ +{ + struct timeval tv; + + ut_gettimeofday(&tv, NULL); + + return((ulint) tv.tv_sec * 1000 + tv.tv_usec / 1000); +} +#endif /* !UNIV_HOTBACKUP */ + +/**********************************************************//** Returns the difference of two times in seconds. @return time2 - time1 expressed in seconds */ UNIV_INTERN diff --git a/storage/innodb_plugin/win-plugin/README b/storage/innodb_plugin/win-plugin/README deleted file mode 100644 index 00f4e996a3f..00000000000 --- a/storage/innodb_plugin/win-plugin/README +++ /dev/null @@ -1,22 +0,0 @@ -This directory contains patches that need to be applied to the MySQL -source tree in order to build the dynamic plugin on Windows -- -HA_INNODB.DLL. Please note the followings when adding the patches: - -* The patch must be applied from the mysql top-level source directory. - patch -p0 < win-plugin.diff -* The patch filenames end in ".diff". -* All patches here are expected to apply cleanly to the latest MySQL 5.1 - tree when storage/innobase is replaced with this InnoDB branch. - -When applying the patch, the following files will be modified: - - * CMakeLists.txt - * sql/CMakeLists.txt - * win/configure.js - -Also, two new files will be added: - - * sql/mysqld.def - * sql/mysqld_x64.def - -You can get "patch" utility for Windows from http://unxutils.sourceforge.net/ diff --git a/storage/innodb_plugin/win-plugin/win-plugin.diff b/storage/innodb_plugin/win-plugin/win-plugin.diff deleted file mode 100644 index 4b3354ac4de..00000000000 --- a/storage/innodb_plugin/win-plugin/win-plugin.diff +++ /dev/null @@ -1,279 +0,0 @@ -diff -Nur CMakeLists.txt.orig CMakeLists.txt ---- CMakeLists.txt.orig 2008-10-03 12:25:41 -05:00 -+++ CMakeLists.txt 2008-09-26 17:32:51 -05:00 -@@ -254,9 +254,9 @@ - IF(WITH_FEDERATED_STORAGE_ENGINE) - ADD_SUBDIRECTORY(storage/federated) - ENDIF(WITH_FEDERATED_STORAGE_ENGINE) --IF(WITH_INNOBASE_STORAGE_ENGINE) -+IF(WITH_INNOBASE_STORAGE_ENGINE OR INNODB_DYNAMIC_PLUGIN) - ADD_SUBDIRECTORY(storage/innobase) --ENDIF(WITH_INNOBASE_STORAGE_ENGINE) -+ENDIF(WITH_INNOBASE_STORAGE_ENGINE OR INNODB_DYNAMIC_PLUGIN) - ADD_SUBDIRECTORY(sql) - ADD_SUBDIRECTORY(server-tools/instance-manager) - ADD_SUBDIRECTORY(libmysql) - -diff -Nur sql/CMakeLists.txt.orig sql/CMakeLists.txt ---- sql/CMakeLists.txt.orig 2008-10-03 12:25:41 -05:00 -+++ sql/CMakeLists.txt 2008-09-24 03:58:19 -05:00 -@@ -98,6 +98,15 @@ - LINK_FLAGS "/PDB:${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb") - ENDIF(cmake_version EQUAL 20406) - -+# Checks for 64-bit version -+IF(CMAKE_SIZEOF_VOID_P MATCHES 8) -+SET_TARGET_PROPERTIES(mysqld PROPERTIES -+ LINK_FLAGS "/def:\"${PROJECT_SOURCE_DIR}/sql/mysqld_x64.def\"") -+ELSE(CMAKE_SIZEOF_VOID_P MATCHES 8) -+SET_TARGET_PROPERTIES(mysqld PROPERTIES -+ LINK_FLAGS "/def:\"${PROJECT_SOURCE_DIR}/sql/mysqld.def\"") -+ENDIF(CMAKE_SIZEOF_VOID_P MATCHES 8) -+ - IF(EMBED_MANIFESTS) - MYSQL_EMBED_MANIFEST("mysqld" "asInvoker") - ENDIF(EMBED_MANIFESTS) - -diff -Nur sql/mysqld.def.orig sql/mysqld.def ---- sql/mysqld.def.orig 1969-12-31 18:00:00 -06:00 -+++ sql/mysqld.def 2009-04-09 02:20:32 -05:00 -@@ -0,0 +1,111 @@ -+EXPORTS -+ ?use_hidden_primary_key@handler@@UAEXXZ -+ ?get_dynamic_partition_info@handler@@UAEXPAUPARTITION_INFO@@I@Z -+ ?read_first_row@handler@@UAEHPAEI@Z -+ ?read_range_next@handler@@UAEHXZ -+ ?read_range_first@handler@@UAEHPBUst_key_range@@0_N1@Z -+ ?read_multi_range_first@handler@@UAEHPAPAUst_key_multi_range@@PAU2@I_NPAUst_handler_buffer@@@Z -+ ?read_multi_range_next@handler@@UAEHPAPAUst_key_multi_range@@@Z -+ ?index_read_idx_map@handler@@UAEHPAEIPBEKW4ha_rkey_function@@@Z -+ ?print_error@handler@@UAEXHH@Z -+ ?clone@handler@@UAEPAV1@PAUst_mem_root@@@Z -+ ?get_auto_increment@handler@@UAEX_K00PA_K1@Z -+ ?index_next_same@handler@@UAEHPAEPBEI@Z -+ ?get_error_message@handler@@UAE_NHPAVString@@@Z -+ ?ha_thd@handler@@IBEPAVTHD@@XZ -+ ?update_auto_increment@handler@@QAEHXZ -+ ?ha_statistic_increment@handler@@IBEXPQsystem_status_var@@K@Z -+ ?trans_register_ha@@YAXPAVTHD@@_NPAUhandlerton@@@Z -+ ?cmp@Field_blob@@QAEHPBEI0I@Z -+ ?set_time@Field_timestamp@@QAEXXZ -+ ?sql_print_error@@YAXPBDZZ -+ ?sql_print_warning@@YAXPBDZZ -+ ?check_global_access@@YA_NPAVTHD@@K@Z -+ ?schema_table_store_record@@YA_NPAVTHD@@PAUst_table@@@Z -+ ?get_quote_char_for_identifier@@YAHPAVTHD@@PBDI@Z -+ ?copy@String@@QAE_NXZ -+ ?copy@String@@QAE_NABV1@@Z -+ ?copy@String@@QAE_NPBDIPAUcharset_info_st@@@Z -+ ?copy_and_convert@@YAIPADIPAUcharset_info_st@@PBDI1PAI@Z -+ ?filename_to_tablename@@YAIPBDPADI@Z -+ ?strconvert@@YAIPAUcharset_info_st@@PBD0PADIPAI@Z -+ ?calculate_key_len@@YAIPAUst_table@@IPBEK@Z -+ ?sql_alloc@@YAPAXI@Z -+ ?localtime_to_TIME@@YAXPAUst_mysql_time@@PAUtm@@@Z -+ ?push_warning@@YAPAVMYSQL_ERROR@@PAVTHD@@W4enum_warning_level@1@IPBD@Z -+ ?push_warning_printf@@YAXPAVTHD@@W4enum_warning_level@MYSQL_ERROR@@IPBDZZ -+ ?drop_table@handler@@EAEXPBD@Z -+ ?column_bitmaps_signal@handler@@UAEXXZ -+ ?delete_table@handler@@MAEHPBD@Z -+ ?rename_table@handler@@MAEHPBD0@Z -+ ?key_map_empty@@3V?$Bitmap@$0EA@@@B -+ ?THR_THD@@3PAVTHD@@A -+ ?end_of_list@@3Ulist_node@@A -+ ?mysql_tmpdir_list@@3Ust_my_tmpdir@@A -+ mysql_query_cache_invalidate4 -+ thd_query -+ thd_sql_command -+ thd_get_thread_id -+ thd_get_xid -+ thd_slave_thread -+ thd_non_transactional_update -+ thd_mark_transaction_to_rollback -+ thd_security_context -+ thd_charset -+ thd_test_options -+ thd_ha_data -+ thd_killed -+ thd_tx_isolation -+ thd_tablespace_op -+ thd_sql_command -+ thd_memdup -+ thd_make_lex_string -+ thd_in_lock_tables -+ thd_binlog_format -+ _my_hash_init -+ my_hash_free -+ my_tmpdir -+ check_if_legal_filename -+ my_filename -+ my_sync_dir_by_file -+ alloc_root -+ thr_lock_data_init -+ thr_lock_init -+ thr_lock_delete -+ my_multi_malloc -+ get_charset -+ unpack_filename -+ my_hash_insert -+ my_hash_search -+ my_hash_delete -+ mysql_bin_log_file_pos -+ mysql_bin_log_file_name -+ mysqld_embedded -+ my_thread_name -+ my_malloc -+ my_no_flags_free -+ _sanity -+ _mymalloc -+ _myfree -+ _my_strdup -+ _my_thread_var -+ my_error -+ pthread_cond_init -+ pthread_cond_signal -+ pthread_cond_wait -+ pthread_cond_destroy -+ localtime_r -+ my_strdup -+ deflate -+ deflateEnd -+ deflateReset -+ deflateInit2_ -+ inflateEnd -+ inflateInit_ -+ inflate -+ compressBound -+ inflateInit2_ -+ adler32 -+ longlong2str -+ strend -+ my_snprintf - -diff -Nur sql/mysqld_x64.def.orig sql/mysqld_x64.def ---- sql/mysqld_x64.def.orig 1969-12-31 18:00:00 -06:00 -+++ sql/mysqld_x64.def 2009-04-09 02:22:04 -05:00 -@@ -0,0 +1,111 @@ -+EXPORTS -+ ?use_hidden_primary_key@handler@@UEAAXXZ -+ ?get_dynamic_partition_info@handler@@UEAAXPEAUPARTITION_INFO@@I@Z -+ ?read_first_row@handler@@UEAAHPEAEI@Z -+ ?read_range_next@handler@@UEAAHXZ -+ ?read_range_first@handler@@UEAAHPEBUst_key_range@@0_N1@Z -+ ?read_multi_range_first@handler@@UEAAHPEAPEAUst_key_multi_range@@PEAU2@I_NPEAUst_handler_buffer@@@Z -+ ?read_multi_range_next@handler@@UEAAHPEAPEAUst_key_multi_range@@@Z -+ ?index_read_idx_map@handler@@UEAAHPEAEIPEBEKW4ha_rkey_function@@@Z -+ ?print_error@handler@@UEAAXHH@Z -+ ?clone@handler@@UEAAPEAV1@PEAUst_mem_root@@@Z -+ ?get_auto_increment@handler@@UEAAX_K00PEA_K1@Z -+ ?index_next_same@handler@@UEAAHPEAEPEBEI@Z -+ ?get_error_message@handler@@UEAA_NHPEAVString@@@Z -+ ?ha_thd@handler@@IEBAPEAVTHD@@XZ -+ ?update_auto_increment@handler@@QEAAHXZ -+ ?ha_statistic_increment@handler@@IEBAXPEQsystem_status_var@@K@Z -+ ?trans_register_ha@@YAXPEAVTHD@@_NPEAUhandlerton@@@Z -+ ?cmp@Field_blob@@QEAAHPEBEI0I@Z -+ ?set_time@Field_timestamp@@QEAAXXZ -+ ?sql_print_error@@YAXPEBDZZ -+ ?sql_print_warning@@YAXPEBDZZ -+ ?check_global_access@@YA_NPEAVTHD@@K@Z -+ ?schema_table_store_record@@YA_NPEAVTHD@@PEAUst_table@@@Z -+ ?get_quote_char_for_identifier@@YAHPEAVTHD@@PEBDI@Z -+ ?copy@String@@QEAA_NXZ -+ ?copy@String@@QEAA_NAEBV1@@Z -+ ?copy@String@@QEAA_NPEBDIPEAUcharset_info_st@@@Z -+ ?copy_and_convert@@YAIPEADIPEAUcharset_info_st@@PEBDI1PEAI@Z -+ ?filename_to_tablename@@YAIPEBDPEADI@Z -+ ?strconvert@@YAIPEAUcharset_info_st@@PEBD0PEADIPEAI@Z -+ ?calculate_key_len@@YAIPEAUst_table@@IPEBEK@Z -+ ?sql_alloc@@YAPEAX_K@Z -+ ?localtime_to_TIME@@YAXPEAUst_mysql_time@@PEAUtm@@@Z -+ ?push_warning@@YAPEAVMYSQL_ERROR@@PEAVTHD@@W4enum_warning_level@1@IPEBD@Z -+ ?push_warning_printf@@YAXPEAVTHD@@W4enum_warning_level@MYSQL_ERROR@@IPEBDZZ -+ ?drop_table@handler@@EEAAXPEBD@Z -+ ?column_bitmaps_signal@handler@@UEAAXXZ -+ ?delete_table@handler@@MEAAHPEBD@Z -+ ?rename_table@handler@@MEAAHPEBD0@Z -+ ?key_map_empty@@3V?$Bitmap@$0EA@@@B -+ ?THR_THD@@3PEAVTHD@@EA -+ ?end_of_list@@3Ulist_node@@A -+ ?mysql_tmpdir_list@@3Ust_my_tmpdir@@A -+ mysql_query_cache_invalidate4 -+ thd_query -+ thd_sql_command -+ thd_get_thread_id -+ thd_get_xid -+ thd_slave_thread -+ thd_non_transactional_update -+ thd_mark_transaction_to_rollback -+ thd_security_context -+ thd_charset -+ thd_test_options -+ thd_ha_data -+ thd_killed -+ thd_tx_isolation -+ thd_tablespace_op -+ thd_sql_command -+ thd_memdup -+ thd_make_lex_string -+ thd_in_lock_tables -+ thd_binlog_format -+ _my_hash_init -+ my_hash_free -+ my_tmpdir -+ check_if_legal_filename -+ my_filename -+ my_sync_dir_by_file -+ alloc_root -+ thr_lock_data_init -+ thr_lock_init -+ thr_lock_delete -+ my_multi_malloc -+ get_charset -+ unpack_filename -+ my_hash_insert -+ my_hash_search -+ my_hash_delete -+ mysql_bin_log_file_pos -+ mysql_bin_log_file_name -+ mysqld_embedded -+ my_thread_name -+ my_malloc -+ my_no_flags_free -+ _sanity -+ _mymalloc -+ _myfree -+ _my_strdup -+ _my_thread_var -+ my_error -+ pthread_cond_init -+ pthread_cond_signal -+ pthread_cond_wait -+ pthread_cond_destroy -+ localtime_r -+ my_strdup -+ deflate -+ deflateEnd -+ deflateReset -+ deflateInit2_ -+ inflateEnd -+ inflateInit_ -+ inflate -+ compressBound -+ inflateInit2_ -+ adler32 -+ longlong2str -+ strend -+ my_snprintf - -diff -Nur win/configure.js.orig win/configure.js ---- win/configure.js.orig 2008-09-26 21:18:37 -05:00 -+++ win/configure.js 2008-10-01 11:21:27 -05:00 -@@ -50,6 +50,7 @@ - case "EMBED_MANIFESTS": - case "EXTRA_DEBUG": - case "WITH_EMBEDDED_SERVER": -+ case "INNODB_DYNAMIC_PLUGIN": - configfile.WriteLine("SET (" + args.Item(i) + " TRUE)"); - break; - case "MYSQL_SERVER_SUFFIX": diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 8719cbd114d..e0e06073b19 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -1928,8 +1928,7 @@ end: bool ha_maria::check_and_repair(THD *thd) { int error, crashed; - char *old_query; - uint old_query_length; + LEX_STRING old_query; HA_CHECK_OPT check_opt; DBUG_ENTER("ha_maria::check_and_repair"); @@ -1957,11 +1956,9 @@ bool ha_maria::check_and_repair(THD *thd) if (!file->state->del && (maria_recover_options & HA_RECOVER_QUICK)) check_opt.flags |= T_QUICK; - old_query= thd->query; - old_query_length= thd->query_length; + old_query= thd->query_string; pthread_mutex_lock(&LOCK_thread_count); - thd->query= table->s->table_name.str; - thd->query_length= table->s->table_name.length; + thd->query_string= table->s->table_name; pthread_mutex_unlock(&LOCK_thread_count); if (!(crashed= maria_is_crashed(file))) @@ -1981,8 +1978,7 @@ bool ha_maria::check_and_repair(THD *thd) error= 1; } pthread_mutex_lock(&LOCK_thread_count); - thd->query= old_query; - thd->query_length= old_query_length; + thd->query_string= old_query; pthread_mutex_unlock(&LOCK_thread_count); DBUG_RETURN(error); } @@ -2292,7 +2288,7 @@ int ha_maria::delete_all_rows() { THD *thd= current_thd; (void) translog_log_debug_info(file->trn, LOGREC_DEBUG_INFO_QUERY, - (uchar*) thd->query, thd->query_length); + (uchar*) thd->query(), thd->query_length()); if (file->s->now_transactional && ((table->in_use->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) || table->in_use->locked_tables)) @@ -2311,7 +2307,7 @@ int ha_maria::delete_table(const char *name) { THD *thd= current_thd; (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY, - (uchar*) thd->query, thd->query_length); + (uchar*) thd->query(), thd->query_length()); return maria_delete_table(name); } @@ -2392,7 +2388,8 @@ int ha_maria::external_lock(THD *thd, int lock_type) trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED | TRN_STATE_TABLES_CAN_CHANGE); (void) translog_log_debug_info(trn, LOGREC_DEBUG_INFO_QUERY, - (uchar*) thd->query, thd->query_length); + (uchar*) thd->query(), + thd->query_length()); } #endif } @@ -2488,7 +2485,8 @@ int ha_maria::start_stmt(THD *thd, thr_lock_type lock_type) { trnman_set_flags(trn, trnman_get_flags(trn) | TRN_STATE_INFO_LOGGED); (void) translog_log_debug_info(trn, LOGREC_DEBUG_INFO_QUERY, - (uchar*) thd->query, thd->query_length); + (uchar*) thd->query(), + thd->query_length()); } #endif } @@ -2769,7 +2767,7 @@ int ha_maria::create(const char *name, register TABLE *table_arg, create_flags|= HA_CREATE_PAGE_CHECKSUM; (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY, - (uchar*) thd->query, thd->query_length); + (uchar*) thd->query(), thd->query_length()); /* TODO: Check that the following fn_format is really needed */ error= @@ -2789,7 +2787,7 @@ int ha_maria::rename_table(const char *from, const char *to) { THD *thd= current_thd; (void) translog_log_debug_info(0, LOGREC_DEBUG_INFO_QUERY, - (uchar*) thd->query, thd->query_length); + (uchar*) thd->query(), thd->query_length()); return maria_rename(from, to); } diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index fd35410682e..d9a99118f24 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -115,6 +115,10 @@ static void mi_check_print_msg(HA_CHECK *param, const char* msg_type, Also we likely need to lock mutex here (in both cases with protocol and push_warning). */ +#ifdef THREAD + if (param->need_print_msg_lock) + pthread_mutex_lock(¶m->print_msg_mutex); +#endif protocol->prepare_for_resend(); protocol->store(name, length, system_charset_info); protocol->store(param->op_name, system_charset_info); @@ -123,6 +127,10 @@ static void mi_check_print_msg(HA_CHECK *param, const char* msg_type, if (protocol->write()) sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n", msgbuf); +#ifdef THREAD + if (param->need_print_msg_lock) + pthread_mutex_unlock(¶m->print_msg_mutex); +#endif return; } @@ -1112,22 +1120,6 @@ int ha_myisam::repair(THD *thd, HA_CHECK ¶m, bool do_optimize) ha_rows rows= file->state->records; DBUG_ENTER("ha_myisam::repair"); - /* - Normally this method is entered with a properly opened table. If the - repair fails, it can be repeated with more elaborate options. Under - special circumstances it can happen that a repair fails so that it - closed the data file and cannot re-open it. In this case file->dfile - is set to -1. We must not try another repair without an open data - file. (Bug #25289) - */ - if (file->dfile == -1) - { - sql_print_information("Retrying repair of: '%s' failed. " - "Please try REPAIR EXTENDED or myisamchk", - table->s->path.str); - DBUG_RETURN(HA_ADMIN_FAILED); - } - param.db_name= table->s->db.str; param.table_name= table->alias; param.tmpfile_createflag = O_RDWR | O_TRUNC; @@ -1636,8 +1628,8 @@ bool ha_myisam::check_and_repair(THD *thd) check_opt.flags|=T_QUICK; sql_print_warning("Checking table: '%s'",table->s->path.str); - old_query= thd->query; - old_query_length= thd->query_length; + old_query= thd->query(); + old_query_length= thd->query_length(); thd->set_query(table->s->table_name.str, (uint) table->s->table_name.length); diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index c6140e0bcd8..a1034addb19 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -89,10 +89,10 @@ static void set_data_file_type(MI_SORT_INFO *sort_info, MYISAM_SHARE *share); void myisamchk_init(HA_CHECK *param) { bzero((uchar*) param,sizeof(*param)); + /* Set all params that are not 0 */ param->opt_follow_links=1; param->keys_in_use= ~(ulonglong) 0; param->search_after_block=HA_OFFSET_ERROR; - param->auto_increment_value= 0; param->use_buffers=USE_BUFFER_INIT; param->read_buffer_length=READ_BUFFER_INIT; param->write_buffer_length=READ_BUFFER_INIT; @@ -100,7 +100,6 @@ void myisamchk_init(HA_CHECK *param) param->sort_key_blocks=BUFFERS_WHEN_SORTING; param->tmpfile_createflag=O_RDWR | O_TRUNC | O_EXCL; param->myf_rw=MYF(MY_NABP | MY_WME | MY_WAIT_IF_FULL); - param->start_check_pos=0; param->max_record_length= LONGLONG_MAX; param->key_cache_block_size= KEY_CACHE_BLOCK_SIZE; param->stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL; @@ -1546,6 +1545,8 @@ int mi_repair(HA_CHECK *param, register MI_INFO *info, if (info->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD)) param->testflag|=T_CALC_CHECKSUM; + DBUG_ASSERT(param->use_buffers < SIZE_T_MAX); + if (!param->using_global_keycache) VOID(init_key_cache(dflt_key_cache, param->key_cache_block_size, (size_t) param->use_buffers, 0, 0)); @@ -2560,8 +2561,9 @@ err: VOID(my_close(new_file,MYF(0))); VOID(my_raid_delete(param->temp_filename,share->base.raid_chunks, MYF(MY_WME))); - if (info->dfile == new_file) - info->dfile= -1; + if (info->dfile == new_file) /* Retry with key cache */ + if (unlikely(mi_open_datafile(info, share, name, -1))) + param->retry_repair= 0; /* Safety */ } mi_mark_crashed_on_repair(info); } @@ -2701,6 +2703,8 @@ int mi_repair_parallel(HA_CHECK *param, register MI_INFO *info, /* Initialize pthread structures before goto err. */ pthread_mutex_init(&sort_info.mutex, MY_MUTEX_INIT_FAST); pthread_cond_init(&sort_info.cond, 0); + pthread_mutex_init(¶m->print_msg_mutex, MY_MUTEX_INIT_FAST); + param->need_print_msg_lock= 1; if (!(sort_info.key_block= alloc_key_blocks(param, (uint) param->sort_key_blocks, @@ -3094,8 +3098,9 @@ err: VOID(my_close(new_file,MYF(0))); VOID(my_raid_delete(param->temp_filename,share->base.raid_chunks, MYF(MY_WME))); - if (info->dfile == new_file) - info->dfile= -1; + if (info->dfile == new_file) /* Retry with key cache */ + if (unlikely(mi_open_datafile(info, share, name, -1))) + param->retry_repair= 0; /* Safety */ } mi_mark_crashed_on_repair(info); } @@ -3105,6 +3110,8 @@ err: pthread_cond_destroy (&sort_info.cond); pthread_mutex_destroy(&sort_info.mutex); + pthread_mutex_destroy(¶m->print_msg_mutex); + param->need_print_msg_lock= 0; my_free((uchar*) sort_info.ft_buf, MYF(MY_ALLOW_ZERO_PTR)); my_free((uchar*) sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR)); diff --git a/storage/myisam/mi_search.c b/storage/myisam/mi_search.c index f03311e6ce4..52d2eb6e10c 100644 --- a/storage/myisam/mi_search.c +++ b/storage/myisam/mi_search.c @@ -302,7 +302,8 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, uchar *end, *kseg, *vseg; uchar *sort_order=keyinfo->seg->charset->sort_order; uchar tt_buff[HA_MAX_KEY_BUFF+2], *t_buff=tt_buff+2; - uchar *saved_from, *saved_to, *saved_vseg; + uchar *UNINIT_VAR(saved_from), *UNINIT_VAR(saved_to); + uchar *UNINIT_VAR(saved_vseg); uint saved_length=0, saved_prefix_len=0; uint length_pack; DBUG_ENTER("_mi_prefix_search"); @@ -310,9 +311,6 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, LINT_INIT(length); LINT_INIT(prefix_len); LINT_INIT(seg_len_pack); - LINT_INIT(saved_from); - LINT_INIT(saved_to); - LINT_INIT(saved_vseg); t_buff[0]=0; /* Avoid bugs */ end= page+mi_getint(page); diff --git a/storage/myisam/mi_write.c b/storage/myisam/mi_write.c index 4cea6bbba85..f2528f2ec60 100644 --- a/storage/myisam/mi_write.c +++ b/storage/myisam/mi_write.c @@ -702,11 +702,11 @@ uchar *_mi_find_half_pos(uint nod_flag, MI_KEYDEF *keyinfo, uchar *page, } /* _mi_find_half_pos */ - /* - Split buffer at last key - Returns pointer to the start of the key before the last key - key will contain the last key - */ +/* + Split buffer at last key + Returns pointer to the start of the key before the last key + key will contain the last key +*/ static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page, uchar *key, uint *return_key_length, @@ -717,6 +717,8 @@ static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page, uchar key_buff[HA_MAX_KEY_BUFF]; DBUG_ENTER("_mi_find_last_pos"); + LINT_INIT(last_length); + key_ref_length=2; length=mi_getint(page)-key_ref_length; page+=key_ref_length; @@ -732,8 +734,6 @@ static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page, DBUG_RETURN(end); } - LINT_INIT(prevpos); - LINT_INIT(last_length); end=page+length-key_ref_length; *key='\0'; length=0; diff --git a/storage/myisam/myisamchk.c b/storage/myisam/myisamchk.c index 6b3ea48e040..06cc22dbd25 100644 --- a/storage/myisam/myisamchk.c +++ b/storage/myisam/myisamchk.c @@ -302,17 +302,17 @@ static struct my_option my_long_options[] = (uchar**) &check_param.read_buffer_length, (uchar**) &check_param.read_buffer_length, 0, GET_ULONG, REQUIRED_ARG, (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD, - (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0}, + INT_MAX32, (long) MALLOC_OVERHEAD, (long) 1L, 0}, { "write_buffer_size", OPT_WRITE_BUFFER_SIZE, "", (uchar**) &check_param.write_buffer_length, (uchar**) &check_param.write_buffer_length, 0, GET_ULONG, REQUIRED_ARG, (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD, - (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0}, + INT_MAX32, (long) MALLOC_OVERHEAD, (long) 1L, 0}, { "sort_buffer_size", OPT_SORT_BUFFER_SIZE, "", (uchar**) &check_param.sort_buffer_length, (uchar**) &check_param.sort_buffer_length, 0, GET_ULONG, REQUIRED_ARG, (long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD), - (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0}, + ULONG_MAX, (long) MALLOC_OVERHEAD, (long) 1L, 0}, { "sort_key_blocks", OPT_SORT_KEY_BLOCKS, "", (uchar**) &check_param.sort_key_blocks, (uchar**) &check_param.sort_key_blocks, 0, GET_ULONG, REQUIRED_ARG, @@ -837,7 +837,7 @@ static int myisamchk(HA_CHECK *param, char * filename) mi_check_print_error(param,"'%s' is marked as crashed after last repair",filename); break; case HA_ERR_OLD_FILE: - mi_check_print_error(param,"'%s' is a old type of MyISAM-table", filename); + mi_check_print_error(param,"'%s' is an old type of MyISAM-table", filename); break; case HA_ERR_END_OF_FILE: mi_check_print_error(param,"Couldn't read complete header from '%s'", filename); diff --git a/storage/myisam/sort.c b/storage/myisam/sort.c index 3aaef41e1dd..80f4942f1f9 100644 --- a/storage/myisam/sort.c +++ b/storage/myisam/sort.c @@ -466,8 +466,12 @@ ok: Detach from the share if the writer is involved. Avoid others to be blocked. This includes a flush of the write buffer. This will also indicate EOF to the readers. + That means that a writer always gets here first and readers - + only when they see EOF. But if a reader finishes prematurely + because of an error it may reach this earlier - don't allow it + to detach the writer thread. */ - if (sort_param->sort_info->info->rec_cache.share) + if (sort_param->master && sort_param->sort_info->info->rec_cache.share) remove_io_thread(&sort_param->sort_info->info->rec_cache); /* Readers detach from the share if any. Avoid others to be blocked. */ @@ -788,7 +792,12 @@ static int NEAR_F merge_many_buff(MI_SORT_PARAM *info, uint keys, cleanup: close_cached_file(to_file); /* This holds old result */ if (to_file == t_file) + { + DBUG_ASSERT(t_file2.type == WRITE_CACHE); *t_file=t_file2; /* Copy result file */ + t_file->current_pos= &t_file->write_pos; + t_file->current_end= &t_file->write_end; + } DBUG_RETURN(*maxbuffer >= MERGEBUFF2); /* Return 1 if interrupted */ } /* merge_many_buff */ diff --git a/storage/myisammrg/myrg_open.c b/storage/myisammrg/myrg_open.c index b82e3682ebf..7b310dc2eed 100644 --- a/storage/myisammrg/myrg_open.c +++ b/storage/myisammrg/myrg_open.c @@ -392,7 +392,7 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking, int save_errno; uint idx; uint child_nr; - uint key_parts; + uint UNINIT_VAR(key_parts); uint min_keys; my_bool bad_children= FALSE; DBUG_ENTER("myrg_attach_children"); @@ -409,7 +409,6 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking, rc= 1; errpos= 0; file_offset= 0; - LINT_INIT(key_parts); min_keys= 0; child_nr= 0; while ((myisam= (*callback)(callback_param))) diff --git a/storage/mysql_storage_engine.cmake b/storage/mysql_storage_engine.cmake index bb368494898..af8c3a85cd1 100644 --- a/storage/mysql_storage_engine.cmake +++ b/storage/mysql_storage_engine.cmake @@ -7,6 +7,8 @@ # Remarks: # ${engine}_SOURCES variable containing source files to produce the library must set before # calling this macro +# ${engine}_LIBS variable containing extra libraries to link with may be set + MACRO(MYSQL_STORAGE_ENGINE engine) IF(NOT SOURCE_SUBLIBS) @@ -22,6 +24,9 @@ IF(NOT SOURCE_SUBLIBS) #Create static library. The name of the library is <storage_engine>.lib ADD_LIBRARY(${libname} ${${engine}_SOURCES}) ADD_DEPENDENCIES(${libname} GenError) + IF(${engine}_LIBS) + TARGET_LINK_LIBRARIES(${libname} ${${engine}_LIBS}) + ENDIF(${engine}_LIBS) MESSAGE("build ${engine} as static library") ELSEIF(${ENGINE_BUILD_TYPE} STREQUAL "DYNAMIC") ADD_DEFINITIONS(-DMYSQL_DYNAMIC_PLUGIN) @@ -30,6 +35,9 @@ IF(NOT SOURCE_SUBLIBS) SET(dyn_libname ha_${libname}) ADD_LIBRARY(${dyn_libname} SHARED ${${engine}_SOURCES}) TARGET_LINK_LIBRARIES (${dyn_libname} mysqld) + IF(${engine}_LIBS) + TARGET_LINK_LIBRARIES(${dyn_libname} ${${engine}_LIBS}) + ENDIF(${engine}_LIBS) MESSAGE("build ${engine} as DLL") ENDIF(${ENGINE_BUILD_TYPE} STREQUAL "STATIC") ENDIF(NOT SOURCE_SUBLIBS) diff --git a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index bc8adf6fd32..11e8c1cc191 100644 --- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -14831,7 +14831,7 @@ void Dblqh::srLogLimits(Signal* signal) while(true) { ndbrequire(tmbyte < clogFileSize); if (logPartPtr.p->logExecState == LogPartRecord::LES_SEARCH_STOP) { - if (logFilePtr.p->logMaxGciCompleted[tmbyte] < logPartPtr.p->logLastGci) { + if (logFilePtr.p->logMaxGciCompleted[tmbyte] <= logPartPtr.p->logLastGci) { jam(); /* -------------------------------------------------------------------- * WE ARE STEPPING BACKWARDS FROM MBYTE TO MBYTE. THIS IS THE FIRST diff --git a/storage/ndb/src/kernel/blocks/suma/Suma.cpp b/storage/ndb/src/kernel/blocks/suma/Suma.cpp index 5f0510cf43a..9179cf7fbbd 100644 --- a/storage/ndb/src/kernel/blocks/suma/Suma.cpp +++ b/storage/ndb/src/kernel/blocks/suma/Suma.cpp @@ -274,7 +274,7 @@ Suma::execSTTOR(Signal* signal) { jam(); send_start_me_req(signal); - return; + DBUG_VOID_RETURN; } } @@ -322,7 +322,7 @@ Suma::execSTTOR(Signal* signal) { if (ERROR_INSERTED(13030)) { ndbout_c("Dont start handover"); - return; + DBUG_VOID_RETURN; } }//if @@ -332,7 +332,7 @@ Suma::execSTTOR(Signal* signal) { * Allow API's to connect */ sendSTTORRY(signal); - return; + DBUG_VOID_RETURN; } if(startphase == 101) @@ -345,7 +345,7 @@ Suma::execSTTOR(Signal* signal) { */ c_startup.m_wait_handover= true; check_start_handover(signal); - return; + DBUG_VOID_RETURN; } } sendSTTORRY(signal); @@ -575,19 +575,19 @@ void Suma::execAPI_FAILREQ(Signal* signal) jam(); sendSignalWithDelay(reference(), GSN_API_FAILREQ, signal, 200, signal->getLength()); - return; + DBUG_VOID_RETURN; } if (c_failedApiNodes.get(failedApiNode)) { jam(); - return; + DBUG_VOID_RETURN; } if (!c_subscriber_nodes.get(failedApiNode)) { jam(); - return; + DBUG_VOID_RETURN; } c_failedApiNodes.set(failedApiNode); @@ -2453,7 +2453,7 @@ Suma::execSUB_START_REQ(Signal* signal){ jam(); c_subscriberPool.release(subbPtr); sendSubStartRef(signal, SubStartRef::PartiallyConnected); - return; + DBUG_VOID_RETURN; } DBUG_PRINT("info",("c_subscriberPool size: %d free: %d", @@ -4289,7 +4289,7 @@ Suma::Restart::runSUMA_START_ME_REQ(Signal* signal, Uint32 sumaRef) ref->errorCode = SumaStartMeRef::Busy; suma.sendSignal(sumaRef, GSN_SUMA_START_ME_REF, signal, SumaStartMeRef::SignalLength, JBB); - return; + DBUG_VOID_RETURN; } nodeId = refToNode(sumaRef); diff --git a/storage/pbxt/src/discover_xt.cc b/storage/pbxt/src/discover_xt.cc index 1bb6e874a1c..fb279bc8d2b 100644 --- a/storage/pbxt/src/discover_xt.cc +++ b/storage/pbxt/src/discover_xt.cc @@ -1256,7 +1256,7 @@ static bool mysql_create_table_no_lock(THD *thd, (!thd->current_stmt_binlog_row_based || (thd->current_stmt_binlog_row_based && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)))) - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); error= FALSE; unlock_and_end: pthread_mutex_unlock(&LOCK_open); diff --git a/storage/xtradb/dict/dict0dict.c b/storage/xtradb/dict/dict0dict.c index 68fa5fccf64..595ce2ed82c 100644 --- a/storage/xtradb/dict/dict0dict.c +++ b/storage/xtradb/dict/dict0dict.c @@ -1238,7 +1238,7 @@ dict_col_name_is_reserved( ulint i; for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) { - if (strcmp(name, reserved_names[i]) == 0) { + if (innobase_strcasecmp(name, reserved_names[i]) == 0) { return(TRUE); } diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 4ca5bd486f6..5eae59184ca 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -111,6 +111,7 @@ static ulong commit_threads = 0; static pthread_mutex_t commit_threads_m; static pthread_cond_t commit_cond; static pthread_mutex_t commit_cond_m; +static pthread_mutex_t analyze_mutex; static bool innodb_inited = 0; #define INSIDE_HA_INNOBASE_CC @@ -234,6 +235,9 @@ static int innobase_release_savepoint(handlerton *hton, THD* thd, static handler *innobase_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root); +/* "GEN_CLUST_INDEX" is the name reserved for Innodb default +system primary index. */ +static const char innobase_index_reserve_name[]= "GEN_CLUST_INDEX"; /**************************************************************** Validate the file format name and return its corresponding id. */ @@ -2393,6 +2397,7 @@ skip_overwrite: pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST); pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST); pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST); + pthread_mutex_init(&analyze_mutex, MY_MUTEX_INIT_FAST); pthread_cond_init(&commit_cond, NULL); innodb_inited= 1; #ifdef MYSQL_DYNAMIC_PLUGIN @@ -2444,6 +2449,7 @@ innobase_end(handlerton *hton, ha_panic_function type) pthread_mutex_destroy(&prepare_commit_mutex); pthread_mutex_destroy(&commit_threads_m); pthread_mutex_destroy(&commit_cond_m); + pthread_mutex_destroy(&analyze_mutex); pthread_cond_destroy(&commit_cond); } @@ -3837,7 +3843,11 @@ ha_innobase::store_key_val_for_row( } else if (mysql_type == MYSQL_TYPE_TINY_BLOB || mysql_type == MYSQL_TYPE_MEDIUM_BLOB || mysql_type == MYSQL_TYPE_BLOB - || mysql_type == MYSQL_TYPE_LONG_BLOB) { + || mysql_type == MYSQL_TYPE_LONG_BLOB + /* MYSQL_TYPE_GEOMETRY data is treated + as BLOB data in innodb. */ + || mysql_type == MYSQL_TYPE_GEOMETRY) { + CHARSET_INFO* cs; ulint key_len; @@ -5818,6 +5828,28 @@ create_table_def( } } + /* First check whether the column to be added has a + system reserved name. */ + if (dict_col_name_is_reserved(field->field_name)){ + push_warning_printf( + (THD*) trx->mysql_thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_CREATE_TABLE, + "Error creating table '%s' with " + "column name '%s'. '%s' is a " + "reserved name. Please try to " + "re-create the table with a " + "different column name.", + table->name, (char*) field->field_name, + (char*) field->field_name); + + dict_mem_table_free(table); + trx_commit_for_mysql(trx); + + error = DB_ERROR; + goto error_ret; + } + dict_mem_table_add_col(table, table->heap, (char*) field->field_name, col_type, @@ -5831,6 +5863,7 @@ create_table_def( error = row_create_table_for_mysql(table, trx); +error_ret: error = convert_error_code_to_mysql(error, flags, NULL); DBUG_RETURN(error); @@ -5869,6 +5902,9 @@ create_index( n_fields = key->key_parts; + /* Assert that "GEN_CLUST_INDEX" cannot be used as non-primary index */ + ut_a(innobase_strcasecmp(key->name, innobase_index_reserve_name) != 0); + ind_type = 0; if (key_num == form->s->primary_key) { @@ -5978,7 +6014,8 @@ create_clustered_index_when_no_primary( /* We pass 0 as the space id, and determine at a lower level the space id where to store the table */ - index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX", + index = dict_mem_index_create(table_name, + innobase_index_reserve_name, 0, DICT_CLUSTERED, 0); error = row_create_index_for_mysql(index, trx, NULL); @@ -6404,14 +6441,6 @@ ha_innobase::create( flags = DICT_TF_COMPACT; } - error = create_table_def(trx, form, norm_name, - create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, - flags); - - if (error) { - goto cleanup; - } - /* Look for a primary key */ primary_key_no= (form->s->primary_key != MAX_KEY ? @@ -6421,7 +6450,23 @@ ha_innobase::create( /* Our function row_get_mysql_key_number_for_index assumes the primary key is always number 0, if it exists */ - DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0); + ut_a(primary_key_no == -1 || primary_key_no == 0); + + /* Check for name conflicts (with reserved name) for + any user indices to be created. */ + if (innobase_index_name_is_reserved(trx, form->key_info, + form->s->keys)) { + error = -1; + goto cleanup; + } + + error = create_table_def(trx, form, norm_name, + create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, + flags); + + if (error) { + goto cleanup; + } /* Create the keys */ @@ -6496,18 +6541,22 @@ ha_innobase::create( setup at this stage and so we use thd. */ /* We need to copy the AUTOINC value from the old table if - this is an ALTER TABLE. */ + this is an ALTER TABLE or CREATE INDEX because CREATE INDEX + does a table copy too. */ if (((create_info->used_fields & HA_CREATE_USED_AUTO) - || thd_sql_command(thd) == SQLCOM_ALTER_TABLE) - && create_info->auto_increment_value != 0) { - - /* Query was ALTER TABLE...AUTO_INCREMENT = x; or - CREATE TABLE ...AUTO_INCREMENT = x; Find out a table - definition from the dictionary and get the current value - of the auto increment field. Set a new value to the - auto increment field if the value is greater than the - maximum value in the column. */ + || thd_sql_command(thd) == SQLCOM_ALTER_TABLE + || thd_sql_command(thd) == SQLCOM_CREATE_INDEX) + && create_info->auto_increment_value > 0) { + + /* Query was one of : + CREATE TABLE ...AUTO_INCREMENT = x; or + ALTER TABLE...AUTO_INCREMENT = x; or + CREATE INDEX x on t(...); + Find out a table definition from the dictionary and get + the current value of the auto increment field. Set a new + value to the auto increment field if the value is greater + than the maximum value in the column. */ auto_inc_value = create_info->auto_increment_value; @@ -7367,9 +7416,15 @@ ha_innobase::analyze( THD* thd, /* in: connection thread handle */ HA_CHECK_OPT* check_opt) /* in: currently ignored */ { + /* Serialize ANALYZE TABLE inside InnoDB, see + Bug#38996 Race condition in ANALYZE TABLE */ + pthread_mutex_lock(&analyze_mutex); + /* Simply call ::info() with all the flags */ info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE); + pthread_mutex_unlock(&analyze_mutex); + return(0); } @@ -7965,8 +8020,9 @@ ha_innobase::external_lock( { ulong const binlog_format= thd_binlog_format(thd); ulong const tx_isolation = thd_tx_isolation(ha_thd()); - if (tx_isolation <= ISO_READ_COMMITTED && - binlog_format == BINLOG_FORMAT_STMT) + if (tx_isolation <= ISO_READ_COMMITTED + && binlog_format == BINLOG_FORMAT_STMT + && thd_binlog_filter_ok(thd)) { char buf[256]; my_snprintf(buf, sizeof(buf), @@ -8843,6 +8899,7 @@ ha_innobase::get_auto_increment( AUTOINC counter after attempting to insert the row. */ if (innobase_autoinc_lock_mode != AUTOINC_OLD_STYLE_LOCKING) { ulonglong need; + ulonglong current; ulonglong next_value; ulonglong col_max_value; @@ -8851,11 +8908,13 @@ ha_innobase::get_auto_increment( col_max_value = innobase_get_int_col_max_value( table->next_number_field); + current = *first_value > col_max_value ? autoinc : *first_value; + need = *nb_reserved_values * increment; /* Compute the last value in the interval */ next_value = innobase_next_autoinc( - *first_value, need, offset, col_max_value); + current, need, offset, col_max_value); prebuilt->autoinc_last_value = next_value; @@ -9851,6 +9910,49 @@ static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff) return 0; } +/*********************************************************************** +This function checks each index name for a table against reserved +system default primary index name 'GEN_CLUST_INDEX'. If a name matches, +this function pushes an warning message to the client, and returns true. */ +extern "C" UNIV_INTERN +bool +innobase_index_name_is_reserved( +/*============================*/ + /* out: true if an index name + matches the reserved name */ + const trx_t* trx, /* in: InnoDB transaction handle */ + const KEY* key_info, /* in: Indexes to be created */ + ulint num_of_keys) /* in: Number of indexes to + be created. */ +{ + const KEY* key; + uint key_num; /* index number */ + + for (key_num = 0; key_num < num_of_keys; key_num++) { + key = &key_info[key_num]; + + if (innobase_strcasecmp(key->name, + innobase_index_reserve_name) == 0) { + /* Push warning to mysql */ + push_warning_printf((THD*) trx->mysql_thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WRONG_NAME_FOR_INDEX, + "Cannot Create Index with name " + "'%s'. The name is reserved " + "for the system default primary " + "index.", + innobase_index_reserve_name); + + my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), + innobase_index_reserve_name); + + return(true); + } + } + + return(false); +} + static SHOW_VAR innodb_status_variables_export[]= { {"Innodb", (char*) &show_innodb_vars, SHOW_FUNC}, {NullS, NullS, SHOW_LONG} diff --git a/storage/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h index c08dd3ed173..5f13f2c8b66 100644 --- a/storage/xtradb/handler/ha_innodb.h +++ b/storage/xtradb/handler/ha_innodb.h @@ -257,6 +257,13 @@ int thd_binlog_format(const MYSQL_THD thd); @param all TRUE <=> rollback main transaction. */ void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); + +/** + Check if binary logging is filtered for thread's current db. + @param thd Thread handle + @retval 1 the query is not filtered, 0 otherwise. +*/ +bool thd_binlog_filter_ok(const MYSQL_THD thd); } typedef struct trx_struct trx_t; @@ -281,3 +288,19 @@ innobase_trx_allocate( /*==================*/ /* out: InnoDB transaction handle */ MYSQL_THD thd); /* in: user thread handle */ +/*********************************************************************//** +This function checks each index name for a table against reserved +system default primary index name 'GEN_CLUST_INDEX'. If a name +matches, this function pushes an warning message to the client, +and returns true. */ +extern "C" +bool +innobase_index_name_is_reserved( +/*============================*/ + /* out: true if the index name + matches the reserved name */ + const trx_t* trx, /* in: InnoDB transaction handle */ + const KEY* key_info, /* in: Indexes to be created */ + ulint num_of_keys); /* in: Number of indexes to + be created. */ + diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index 1b5466e66eb..de1bd051e1f 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -655,9 +655,13 @@ ha_innobase::add_index( innodb_table = indexed_table = dict_table_get(prebuilt->table->name, FALSE); - /* Check that index keys are sensible */ - - error = innobase_check_index_keys(key_info, num_of_keys); + /* Check if the index name is reserved. */ + if (innobase_index_name_is_reserved(trx, key_info, num_of_keys)) { + error = ER_WRONG_NAME_FOR_INDEX; + } else { + /* Check that index keys are sensible */ + error = innobase_check_index_keys(key_info, num_of_keys); + } if (UNIV_UNLIKELY(error)) { err_exit: diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index 7de00025eda..4f3aaa6f668 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -185,8 +185,8 @@ int my_strnncollsp_simple(CHARSET_INFO * cs, const uchar *a, size_t a_length, } for (end= a + a_length-length; a < end ; a++) { - if (map[*a] != ' ') - return (map[*a] < ' ') ? -swap : swap; + if (map[*a] != map[' ']) + return (map[*a] < map[' ']) ? -swap : swap; } } return res; diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index 589276dbf23..8a51f9d7f75 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -7858,6 +7858,9 @@ static my_bool create_tailoring(CHARSET_INFO *cs, void *(*alloc)(size_t)) return 1; } + if (!cs->caseinfo) + cs->caseinfo= my_unicase_default; + if (!(newweights= (uint16**) (*alloc)(256*sizeof(uint16*)))) return 1; bzero(newweights, 256*sizeof(uint16*)); diff --git a/support-files/binary-configure.sh b/support-files/binary-configure.sh index 884a8363e22..5e6d62f69a0 100644 --- a/support-files/binary-configure.sh +++ b/support-files/binary-configure.sh @@ -1,4 +1,28 @@ #!/bin/sh + +SCRIPT_NAME="`basename $0`" + +usage() +{ + echo "Usage: ${SCRIPT_NAME} [--help|-h]" + echo "" + echo "This script creates the MySQL system tables and starts the server." +} + +for arg do + case "$arg" in + --help|-h) + usage + exit 0 + ;; + *) + echo "${SCRIPT_NAME}: unknown option $arg" + usage + exit 2 + ;; + esac +done + if test ! -x ./scripts/mysql_install_db then echo "I didn't find the script './scripts/mysql_install_db'." diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index b126e12712f..0efe779c7bc 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -49,6 +49,9 @@ static char *opt_user= 0; static char *opt_password= 0; static char *opt_host= 0; static char *opt_unix_socket= 0; +#ifdef HAVE_SMEM +static char *shared_memory_base_name= 0; +#endif static unsigned int opt_port; static my_bool tty_password= 0, opt_silent= 0; @@ -233,6 +236,26 @@ static void print_st_error(MYSQL_STMT *stmt, const char *msg) } } +/* + Enhanced version of mysql_client_init(), which may also set shared memory + base on Windows. +*/ +static MYSQL *mysql_client_init(MYSQL* con) +{ + MYSQL* res = mysql_init(con); +#ifdef HAVE_SMEM + if (res && shared_memory_base_name) + mysql_options(res, MYSQL_SHARED_MEMORY_BASE_NAME, shared_memory_base_name); +#endif + return res; +} + +/* + Disable direct calls of mysql_init, as it disregards shared memory base. +*/ +#define mysql_init(A) Please use mysql_client_init instead of mysql_init + + /* Check if the connection has InnoDB tables */ static my_bool check_have_innodb(MYSQL *conn) @@ -296,10 +319,10 @@ static MYSQL* client_connect(ulong flag, uint protocol, my_bool auto_reconnect) fprintf(stdout, "\n Establishing a connection to '%s' ...", opt_host ? opt_host : ""); - if (!(mysql= mysql_init(NULL))) + if (!(mysql= mysql_client_init(NULL))) { opt_silent= 0; - myerror("mysql_init() failed"); + myerror("mysql_client_init() failed"); exit(1); } /* enable local infile, in non-binary builds often disabled by default */ @@ -1165,9 +1188,9 @@ static my_bool thread_query(const char *query) error= 0; if (!opt_silent) fprintf(stdout, "\n in thread_query(%s)", query); - if (!(l_mysql= mysql_init(NULL))) + if (!(l_mysql= mysql_client_init(NULL))) { - myerror("mysql_init() failed"); + myerror("mysql_client_init() failed"); return 1; } if (!(mysql_real_connect(l_mysql, opt_host, opt_user, @@ -2517,9 +2540,9 @@ static void test_ps_query_cache() case TEST_QCACHE_ON_WITH_OTHER_CONN: if (!opt_silent) fprintf(stdout, "\n Establishing a test connection ..."); - if (!(lmysql= mysql_init(NULL))) + if (!(lmysql= mysql_client_init(NULL))) { - printf("mysql_init() failed"); + printf("mysql_client_init() failed"); DIE_UNLESS(0); } if (!(mysql_real_connect(lmysql, opt_host, opt_user, @@ -4965,9 +4988,9 @@ static void test_stmt_close() if (!opt_silent) fprintf(stdout, "\n Establishing a test connection ..."); - if (!(lmysql= mysql_init(NULL))) + if (!(lmysql= mysql_client_init(NULL))) { - myerror("mysql_init() failed"); + myerror("mysql_client_init() failed"); exit(1); } if (!(mysql_real_connect(lmysql, opt_host, opt_user, @@ -5856,9 +5879,9 @@ DROP TABLE IF EXISTS test_multi_tab"; rc= mysql_more_results(mysql); DIE_UNLESS(rc == 0); - if (!(mysql_local= mysql_init(NULL))) + if (!(mysql_local= mysql_client_init(NULL))) { - fprintf(stdout, "\n mysql_init() failed"); + fprintf(stdout, "\n mysql_client_init() failed"); exit(1); } @@ -5981,9 +6004,9 @@ static void test_prepare_multi_statements() char query[MAX_TEST_QUERY_LENGTH]; myheader("test_prepare_multi_statements"); - if (!(mysql_local= mysql_init(NULL))) + if (!(mysql_local= mysql_client_init(NULL))) { - fprintf(stderr, "\n mysql_init() failed"); + fprintf(stderr, "\n mysql_client_init() failed"); exit(1); } @@ -7464,9 +7487,9 @@ static void test_prepare_grant() if (!opt_silent) fprintf(stdout, "\n Establishing a test connection ..."); - if (!(lmysql= mysql_init(NULL))) + if (!(lmysql= mysql_client_init(NULL))) { - myerror("mysql_init() failed"); + myerror("mysql_client_init() failed"); exit(1); } if (!(mysql_real_connect(lmysql, opt_host, "test_grant", @@ -7921,9 +7944,9 @@ static void test_drop_temp() if (!opt_silent) fprintf(stdout, "\n Establishing a test connection ..."); - if (!(lmysql= mysql_init(NULL))) + if (!(lmysql= mysql_client_init(NULL))) { - myerror("mysql_init() failed"); + myerror("mysql_client_init() failed"); exit(1); } @@ -13165,7 +13188,7 @@ static void test_bug15518() int rc; myheader("test_bug15518"); - mysql1= mysql_init(NULL); + mysql1= mysql_client_init(NULL); if (!mysql_real_connect(mysql1, opt_host, opt_user, opt_password, opt_db ? opt_db : "test", opt_port, opt_unix_socket, @@ -13321,9 +13344,9 @@ static void test_bug8378() if (!opt_silent) fprintf(stdout, "\n Establishing a test connection ..."); - if (!(lmysql= mysql_init(NULL))) + if (!(lmysql= mysql_client_init(NULL))) { - myerror("mysql_init() failed"); + myerror("mysql_client_init() failed"); exit(1); } if (mysql_options(lmysql, MYSQL_SET_CHARSET_NAME, "gbk")) @@ -13862,7 +13885,7 @@ static void test_bug9992() if (!opt_silent) printf("Establishing a connection with option CLIENT_MULTI_STATEMENTS..\n"); - mysql1= mysql_init(NULL); + mysql1= mysql_client_init(NULL); if (!mysql_real_connect(mysql1, opt_host, opt_user, opt_password, opt_db ? opt_db : "test", opt_port, opt_unix_socket, @@ -14451,9 +14474,9 @@ static void test_bug12001() myheader("test_bug12001"); - if (!(mysql_local= mysql_init(NULL))) + if (!(mysql_local= mysql_client_init(NULL))) { - fprintf(stdout, "\n mysql_init() failed"); + fprintf(stdout, "\n mysql_client_init() failed"); exit(1); } @@ -15178,9 +15201,9 @@ static void test_opt_reconnect() myheader("test_opt_reconnect"); - if (!(lmysql= mysql_init(NULL))) + if (!(lmysql= mysql_client_init(NULL))) { - myerror("mysql_init() failed"); + myerror("mysql_client_init() failed"); exit(1); } @@ -15215,9 +15238,9 @@ static void test_opt_reconnect() mysql_close(lmysql); - if (!(lmysql= mysql_init(NULL))) + if (!(lmysql= mysql_client_init(NULL))) { - myerror("mysql_init() failed"); + myerror("mysql_client_init() failed"); DIE_UNLESS(0); } @@ -15252,7 +15275,7 @@ static void test_bug12744() int rc; myheader("test_bug12744"); - lmysql= mysql_init(NULL); + lmysql= mysql_client_init(NULL); DIE_UNLESS(lmysql); if (!mysql_real_connect(lmysql, opt_host, opt_user, opt_password, @@ -15825,7 +15848,7 @@ static void test_bug15752() rc= mysql_query(mysql, "create procedure p1() select 1"); myquery(rc); - mysql_init(&mysql_local); + mysql_client_init(&mysql_local); if (! mysql_real_connect(&mysql_local, opt_host, opt_user, opt_password, current_db, opt_port, opt_unix_socket, @@ -16712,7 +16735,7 @@ static void test_bug29692() { MYSQL* conn; - if (!(conn= mysql_init(NULL))) + if (!(conn= mysql_client_init(NULL))) { myerror("test_bug29692 init failed"); exit(1); @@ -16847,7 +16870,7 @@ static void test_bug30472() /* Create a new connection. */ - DIE_UNLESS(mysql_init(&con)); + DIE_UNLESS(mysql_client_init(&con)); DIE_UNLESS(mysql_real_connect(&con, opt_host, @@ -17021,7 +17044,7 @@ static void test_bug20023() /* Create a new connection. */ - DIE_UNLESS(mysql_init(&con)); + DIE_UNLESS(mysql_client_init(&con)); DIE_UNLESS(mysql_real_connect(&con, opt_host, @@ -17158,7 +17181,7 @@ static void bug31418_impl() /* Create a new connection. */ - DIE_UNLESS(mysql_init(&con)); + DIE_UNLESS(mysql_client_init(&con)); DIE_UNLESS(mysql_real_connect(&con, opt_host, @@ -18008,7 +18031,7 @@ static void test_bug44495() "END;"); myquery(rc); - DIE_UNLESS(mysql_init(&con)); + DIE_UNLESS(mysql_client_init(&con)); DIE_UNLESS(mysql_real_connect(&con, opt_host, opt_user, opt_password, current_db, opt_port, opt_unix_socket, @@ -18071,6 +18094,11 @@ static struct my_option client_test_long_options[] = 0, 0, 0, 0, 0, 0}, {"silent", 's', "Be more silent", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_SMEM + {"shared-memory-base-name", 'm', "Base name of shared memory.", + (uchar**) &shared_memory_base_name, (uchar**)&shared_memory_base_name, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"socket", 'S', "Socket file to use for connection", (uchar **) &opt_unix_socket, (uchar **) &opt_unix_socket, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, diff --git a/unittest/mysys/Makefile.am b/unittest/mysys/Makefile.am index ab997c79b33..5ceae438aa2 100644 --- a/unittest/mysys/Makefile.am +++ b/unittest/mysys/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2006 MySQL AB +# Copyright (C) 2009 Sun Microsystems, Inc. # # 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 @@ -26,6 +26,14 @@ LDADD = $(top_builddir)/unittest/mytap/libmytap.a \ $(top_builddir)/strings/libmystrings.a EXTRA_DIST = CMakeLists.txt +noinst_PROGRAMS = bitmap-t base64-t + +if NEED_THREAD +# my_atomic-t is used to check thread functions, so it is safe to +# ignore the file in non-threaded builds. +# In fact, it will not compile without thread support. +noinst_PROGRAMS += my_atomic-t +endif # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/vio/vio.c b/vio/vio.c index e088687098b..fd8e2e5a402 100644 --- a/vio/vio.c +++ b/vio/vio.c @@ -43,7 +43,7 @@ static void vio_init(Vio* vio, enum enum_vio_type type, if ((flags & VIO_BUFFERED_READ) && !(vio->read_buffer= (char*)my_malloc(VIO_READ_BUFFER_SIZE, MYF(MY_WME)))) flags&= ~VIO_BUFFERED_READ; -#ifdef __WIN__ +#ifdef _WIN32 if (type == VIO_TYPE_NAMEDPIPE) { vio->viodelete =vio_delete; @@ -59,9 +59,16 @@ static void vio_init(Vio* vio, enum enum_vio_type type, vio->in_addr =vio_in_addr; vio->vioblocking =vio_blocking; vio->is_blocking =vio_is_blocking; - vio->timeout =vio_ignore_timeout; + + vio->timeout=vio_win32_timeout; + /* Set default timeout */ + vio->read_timeout_millis = INFINITE; + vio->write_timeout_millis = INFINITE; + + memset(&(vio->pipe_overlapped), 0, sizeof(OVERLAPPED)); + vio->pipe_overlapped.hEvent= CreateEvent(NULL, TRUE, FALSE, NULL); + DBUG_VOID_RETURN; } - else /* default is VIO_TYPE_TCPIP */ #endif #ifdef HAVE_SMEM if (type == VIO_TYPE_SHARED_MEMORY) @@ -79,9 +86,14 @@ static void vio_init(Vio* vio, enum enum_vio_type type, vio->in_addr =vio_in_addr; vio->vioblocking =vio_blocking; vio->is_blocking =vio_is_blocking; - vio->timeout =vio_ignore_timeout; + + /* Currently, shared memory is on Windows only, hence the below is ok*/ + vio->timeout= vio_win32_timeout; + /* Set default timeout */ + vio->read_timeout_millis= INFINITE; + vio->write_timeout_millis= INFINITE; + DBUG_VOID_RETURN; } - else #endif #ifdef HAVE_OPENSSL if (type == VIO_TYPE_SSL) @@ -100,8 +112,8 @@ static void vio_init(Vio* vio, enum enum_vio_type type, vio->vioblocking =vio_ssl_blocking; vio->is_blocking =vio_is_blocking; vio->timeout =vio_timeout; + DBUG_VOID_RETURN; } - else /* default is VIO_TYPE_TCPIP */ #endif /* HAVE_OPENSSL */ { vio->viodelete =vio_delete; @@ -193,7 +205,7 @@ Vio *vio_new_win32pipe(HANDLE hPipe) } #ifdef HAVE_SMEM -Vio *vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, HANDLE handle_map, +Vio *vio_new_win32shared_memory(HANDLE handle_file_map, HANDLE handle_map, HANDLE event_server_wrote, HANDLE event_server_read, HANDLE event_client_wrote, HANDLE event_client_read, HANDLE event_conn_closed) @@ -212,7 +224,6 @@ Vio *vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, HANDLE handle_m vio->event_conn_closed= event_conn_closed; vio->shared_memory_remain= 0; vio->shared_memory_pos= handle_map; - vio->net= net; strmov(vio->desc, "shared memory"); } DBUG_RETURN(vio); diff --git a/vio/vio_priv.h b/vio/vio_priv.h index b9f5dd0c9c4..b662a616eef 100644 --- a/vio/vio_priv.h +++ b/vio/vio_priv.h @@ -22,7 +22,10 @@ #include <m_string.h> #include <violite.h> -void vio_ignore_timeout(Vio *vio, uint which, uint timeout); +#ifdef _WIN32 +void vio_win32_timeout(Vio *vio, uint which, uint timeout); +#endif + void vio_timeout(Vio *vio,uint which, uint timeout); #ifdef HAVE_OPENSSL diff --git a/vio/viosocket.c b/vio/viosocket.c index fead2ca7c1c..a26d421bc3b 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -261,19 +261,13 @@ int vio_close(Vio * vio) { int r=0; DBUG_ENTER("vio_close"); -#ifdef __WIN__ - if (vio->type == VIO_TYPE_NAMEDPIPE) - { -#if defined(__NT__) && defined(MYSQL_SERVER) - CancelIo(vio->hPipe); - DisconnectNamedPipe(vio->hPipe); -#endif - r=CloseHandle(vio->hPipe); - } - else -#endif /* __WIN__ */ + if (vio->type != VIO_CLOSED) { + DBUG_ASSERT(vio->type == VIO_TYPE_TCPIP || + vio->type == VIO_TYPE_SOCKET || + vio->type == VIO_TYPE_SSL); + DBUG_ASSERT(vio->sd >= 0); if (shutdown(vio->sd, SHUT_RDWR)) r= -1; @@ -430,44 +424,97 @@ void vio_timeout(Vio *vio, uint which, uint timeout) #ifdef __WIN__ -size_t vio_read_pipe(Vio * vio, uchar* buf, size_t size) + +/* + Finish pending IO on pipe. Honor wait timeout +*/ +static int pipe_complete_io(Vio* vio, char* buf, size_t size, DWORD timeout_millis) { DWORD length; + DWORD ret; + + DBUG_ENTER("pipe_complete_io"); + + ret= WaitForSingleObject(vio->pipe_overlapped.hEvent, timeout_millis); + /* + WaitForSingleObjects will normally return WAIT_OBJECT_O (success, IO completed) + or WAIT_TIMEOUT. + */ + if(ret != WAIT_OBJECT_0) + { + CancelIo(vio->hPipe); + DBUG_PRINT("error",("WaitForSingleObject() returned %d", ret)); + DBUG_RETURN(-1); + } + + if (!GetOverlappedResult(vio->hPipe,&(vio->pipe_overlapped),&length, FALSE)) + { + DBUG_PRINT("error",("GetOverlappedResult() returned last error %d", + GetLastError())); + DBUG_RETURN(-1); + } + + DBUG_RETURN(length); +} + + +size_t vio_read_pipe(Vio * vio, uchar *buf, size_t size) +{ + DWORD bytes_read; DBUG_ENTER("vio_read_pipe"); DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %u", vio->sd, (long) buf, (uint) size)); - if (!ReadFile(vio->hPipe, buf, size, &length, NULL)) - DBUG_RETURN(-1); + if (!ReadFile(vio->hPipe, buf, (DWORD)size, &bytes_read, + &(vio->pipe_overlapped))) + { + if (GetLastError() != ERROR_IO_PENDING) + { + DBUG_PRINT("error",("ReadFile() returned last error %d", + GetLastError())); + DBUG_RETURN((size_t)-1); + } + bytes_read= pipe_complete_io(vio, buf, size,vio->read_timeout_millis); + } - DBUG_PRINT("exit", ("%d", length)); - DBUG_RETURN((size_t) length); + DBUG_PRINT("exit", ("%d", bytes_read)); + DBUG_RETURN(bytes_read); } size_t vio_write_pipe(Vio * vio, const uchar* buf, size_t size) { - DWORD length; + DWORD bytes_written; DBUG_ENTER("vio_write_pipe"); DBUG_PRINT("enter", ("sd: %d buf: 0x%lx size: %u", vio->sd, (long) buf, (uint) size)); - if (!WriteFile(vio->hPipe, (char*) buf, size, &length, NULL)) - DBUG_RETURN(-1); + if (!WriteFile(vio->hPipe, buf, (DWORD)size, &bytes_written, + &(vio->pipe_overlapped))) + { + if (GetLastError() != ERROR_IO_PENDING) + { + DBUG_PRINT("vio_error",("WriteFile() returned last error %d", + GetLastError())); + DBUG_RETURN((size_t)-1); + } + bytes_written = pipe_complete_io(vio, (char *)buf, size, + vio->write_timeout_millis); + } - DBUG_PRINT("exit", ("%d", length)); - DBUG_RETURN((size_t) length); + DBUG_PRINT("exit", ("%d", bytes_written)); + DBUG_RETURN(bytes_written); } + int vio_close_pipe(Vio * vio) { int r; DBUG_ENTER("vio_close_pipe"); -#if defined(__NT__) && defined(MYSQL_SERVER) - CancelIo(vio->hPipe); + + CloseHandle(vio->pipe_overlapped.hEvent); DisconnectNamedPipe(vio->hPipe); -#endif - r=CloseHandle(vio->hPipe); + r= CloseHandle(vio->hPipe); if (r) { DBUG_PRINT("vio_error", ("close() failed, error: %d",GetLastError())); @@ -479,10 +526,23 @@ int vio_close_pipe(Vio * vio) } -void vio_ignore_timeout(Vio *vio __attribute__((unused)), - uint which __attribute__((unused)), - uint timeout __attribute__((unused))) +void vio_win32_timeout(Vio *vio, uint which , uint timeout_sec) { + DWORD timeout_millis; + /* + Windows is measuring timeouts in milliseconds. Check for possible int + overflow. + */ + if (timeout_sec > UINT_MAX/1000) + timeout_millis= INFINITE; + else + timeout_millis= timeout_sec * 1000; + + /* which == 1 means "write", which == 0 means "read".*/ + if(which) + vio->write_timeout_millis= timeout_millis; + else + vio->read_timeout_millis= timeout_millis; } @@ -517,7 +577,7 @@ size_t vio_read_shared_memory(Vio * vio, uchar* buf, size_t size) WAIT_ABANDONED_0 and WAIT_TIMEOUT - fail. We can't read anything */ if (WaitForMultipleObjects(array_elements(events), events, FALSE, - vio->net->read_timeout*1000) != WAIT_OBJECT_0) + vio->read_timeout_millis) != WAIT_OBJECT_0) { DBUG_RETURN(-1); }; @@ -574,7 +634,7 @@ size_t vio_write_shared_memory(Vio * vio, const uchar* buf, size_t size) while (remain != 0) { if (WaitForMultipleObjects(array_elements(events), events, FALSE, - vio->net->write_timeout*1000) != WAIT_OBJECT_0) + vio->write_timeout_millis) != WAIT_OBJECT_0) { DBUG_RETURN((size_t) -1); } diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 6a6e08818c6..51d049b18b9 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -144,55 +144,6 @@ vio_set_cert_stuff(SSL_CTX *ctx, const char *cert_file, const char *key_file, } -static int -vio_verify_callback(int ok, X509_STORE_CTX *ctx) -{ - char buf[256]; - X509 *err_cert; - - DBUG_ENTER("vio_verify_callback"); - DBUG_PRINT("enter", ("ok: %d ctx: 0x%lx", ok, (long) ctx)); - - err_cert= X509_STORE_CTX_get_current_cert(ctx); - X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); - DBUG_PRINT("info", ("cert: %s", buf)); - if (!ok) - { - int err, depth; - err= X509_STORE_CTX_get_error(ctx); - depth= X509_STORE_CTX_get_error_depth(ctx); - - DBUG_PRINT("error",("verify error: %d '%s'",err, - X509_verify_cert_error_string(err))); - /* - Approve cert if depth is greater then "verify_depth", currently - verify_depth is always 0 and there is no way to increase it. - */ - if (verify_depth >= depth) - ok= 1; - } - switch (ctx->error) - { - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: - X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256); - DBUG_PRINT("info",("issuer= %s\n", buf)); - break; - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: - DBUG_PRINT("error", ("notBefore")); - /*ASN1_TIME_print_fp(stderr,X509_get_notBefore(ctx->current_cert));*/ - break; - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: - DBUG_PRINT("error", ("notAfter error")); - /*ASN1_TIME_print_fp(stderr,X509_get_notAfter(ctx->current_cert));*/ - break; - } - DBUG_PRINT("exit", ("%d", ok)); - DBUG_RETURN(ok); -} - - #ifdef __NETWARE__ /* NetWare SSL cleanup */ @@ -354,11 +305,7 @@ new_VioSSLConnectorFd(const char *key_file, const char *cert_file, /* Init the VioSSLFd as a "connector" ie. the client side */ - /* - The verify_callback function is used to control the behaviour - when the SSL_VERIFY_PEER flag is set. - */ - SSL_CTX_set_verify(ssl_fd->ssl_context, verify, vio_verify_callback); + SSL_CTX_set_verify(ssl_fd->ssl_context, verify, NULL); return ssl_fd; } @@ -382,11 +329,7 @@ new_VioSSLAcceptorFd(const char *key_file, const char *cert_file, /* Set max number of cached sessions, returns the previous size */ SSL_CTX_sess_set_cache_size(ssl_fd->ssl_context, 128); - /* - The verify_callback function is used to control the behaviour - when the SSL_VERIFY_PEER flag is set. - */ - SSL_CTX_set_verify(ssl_fd->ssl_context, verify, vio_verify_callback); + SSL_CTX_set_verify(ssl_fd->ssl_context, verify, NULL); /* Set session_id - an identifier for this server session |