From 8c65b726a5edd69eb9aee0ea903b2ce2c92ba961 Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Thu, 4 Feb 2010 13:39:42 +0100 Subject: Recommit of Bug#49447. --- sql/mysqld.cc | 199 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 113 insertions(+), 86 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ca20299b36e..7c45fda1e02 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5761,12 +5761,12 @@ struct my_option my_long_options[] = {"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax. This mode will also set transaction isolation level 'serializable'.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"auto-increment-increment", OPT_AUTO_INCREMENT, - "Auto-increment columns are incremented by this", + "Auto-increment columns are incremented by this.", (uchar**) &global_system_variables.auto_increment_increment, (uchar**) &max_system_variables.auto_increment_increment, 0, GET_ULONG, OPT_ARG, 1, 1, 65535, 0, 1, 0 }, {"auto-increment-offset", OPT_AUTO_INCREMENT_OFFSET, - "Offset added to Auto-increment columns. Used when auto-increment-increment != 1", + "Offset added to Auto-increment columns. Used when auto-increment-increment != 1.", (uchar**) &global_system_variables.auto_increment_offset, (uchar**) &max_system_variables.auto_increment_offset, 0, GET_ULONG, OPT_ARG, 1, 1, 65535, 0, 1, 0 }, @@ -5779,7 +5779,7 @@ struct my_option my_long_options[] = (uchar**) &mysql_home_ptr, (uchar**) &mysql_home_ptr, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"big-tables", OPT_BIG_TABLES, - "Allow big result sets by saving all temporary sets on file (Solves most 'table full' errors).", + "Allow big result sets by saving all temporary sets on file (solves most 'table full' errors).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"bind-address", OPT_BIND_ADDRESS, "IP address to bind to.", (uchar**) &my_bind_addr_str, (uchar**) &my_bind_addr_str, 0, GET_STR, @@ -5787,11 +5787,10 @@ struct my_option my_long_options[] = {"binlog_format", OPT_BINLOG_FORMAT, "Does not have any effect without '--log-bin'. " "Tell the master the form of binary logging to use: either 'row' for " - "row-based binary logging, or 'statement' for statement-based binary " + "row-based binary logging, 'statement' for statement-based binary " "logging, or 'mixed'. 'mixed' is statement-based binary logging except " - "for those statements where only row-based is correct: those which " - "involve user-defined functions (i.e. UDFs) or the UUID() function; for " - "those, row-based binary logging is automatically used. " + "for statements where only row-based is correct: Statements that involve " + "user-defined functions (i.e., UDFs) or the UUID() function." #ifdef HAVE_NDB_BINLOG "If ndbcluster is enabled and binlog_format is `mixed', the format switches" " to 'row' and back implicitly per each query accessing a NDB table." @@ -5802,7 +5801,7 @@ struct my_option my_long_options[] = "Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB, - "Tells the master that updates to the given database should not be logged tothe binary log.", + "Tells the master that updates to the given database should not be logged to the binary log.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"binlog-row-event-max-size", OPT_BINLOG_ROWS_EVENT_MAX_SIZE, "The maximum size of a row-based binary log event in bytes. Rows will be " @@ -5846,10 +5845,10 @@ struct my_option my_long_options[] = (uchar**) &max_system_variables.completion_type, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 2, 0, 1, 0}, {"concurrent-insert", OPT_CONCURRENT_INSERT, - "Use concurrent insert with MyISAM. Disable with --concurrent-insert=0", + "Use concurrent insert with MyISAM. Disable with --concurrent-insert=0.", (uchar**) &myisam_concurrent_insert, (uchar**) &myisam_concurrent_insert, 0, GET_ULONG, OPT_ARG, 1, 0, 2, 0, 0, 0}, - {"console", OPT_CONSOLE, "Write error output on screen; Don't remove the console window on windows.", + {"console", OPT_CONSOLE, "Write error output on screen; don't remove the console window on windows.", (uchar**) &opt_console, (uchar**) &opt_console, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"core-file", OPT_WANT_CORE, "Write core on errors.", 0, 0, 0, GET_NO_ARG, @@ -5881,7 +5880,7 @@ struct my_option my_long_options[] = {"delay-key-write", OPT_DELAY_KEY_WRITE, "Type of DELAY_KEY_WRITE.", 0,0,0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"delay-key-write-for-all-tables", OPT_DELAY_KEY_WRITE_ALL, - "Don't flush key buffers between writes for any MyISAM table (Deprecated option, use --delay-key-write=all instead).", + "Don't flush key buffers between writes for any MyISAM table. (Deprecated option, use --delay-key-write=all instead.)", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_OPENSSL {"des-key-file", OPT_DES_KEY_FILE, @@ -5919,7 +5918,7 @@ struct my_option my_long_options[] = /* See how it's handled in get_one_option() */ {"event-scheduler", OPT_EVENT_SCHEDULER, "Enable/disable the event scheduler.", NULL, NULL, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"exit-info", 'T', "Used for debugging; Use at your own risk!", 0, 0, 0, + {"exit-info", 'T', "Used for debugging. Use at your own risk.", 0, 0, 0, GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"external-locking", OPT_USE_LOCKING, "Use system (external) locking (disabled by default). With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running. Disable with --skip-external-locking.", (uchar**) &opt_external_locking, (uchar**) &opt_external_locking, @@ -5929,11 +5928,11 @@ struct my_option my_long_options[] = /* We must always support the next option to make scripts like mysqltest easier to do */ {"gdb", OPT_DEBUGGING, - "Set up signals usable for debugging", + "Set up signals usable for debugging.", (uchar**) &opt_debugging, (uchar**) &opt_debugging, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"general_log", OPT_GENERAL_LOG, - "Enable|disable general log", (uchar**) &opt_log, + "Enable/disable general log.", (uchar**) &opt_log, (uchar**) &opt_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_LARGE_PAGES {"large-pages", OPT_ENABLE_LARGE_PAGES, "Enable support for large pages. \ @@ -5942,9 +5941,10 @@ Disable with --skip-large-pages.", 0, 0, 0}, #endif {"ignore-builtin-innodb", OPT_IGNORE_BUILTIN_INNODB , - "Disable initialization of builtin InnoDB plugin", + "Disable initialization of builtin InnoDB plugin.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"init-connect", OPT_INIT_CONNECT, "Command(s) that are executed for each new connection", + {"init-connect", OPT_INIT_CONNECT, + "Command(s) that are executed for each new connection.", (uchar**) &opt_init_connect, (uchar**) &opt_init_connect, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifndef DISABLE_GRANT_OPTIONS @@ -5968,7 +5968,7 @@ each time the SQL thread starts.", (uchar**) &lc_time_names_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, {"local-infile", OPT_LOCAL_INFILE, - "Enable/disable LOAD DATA LOCAL INFILE (takes values 1|0).", + "Enable/disable LOAD DATA LOCAL INFILE (takes values 1 or 0).", (uchar**) &opt_local_infile, (uchar**) &opt_local_infile, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, @@ -6006,8 +6006,9 @@ each time the SQL thread starts.", */ {"log-bin-trust-function-creators", OPT_LOG_BIN_TRUST_FUNCTION_CREATORS, "If equal to 0 (the default), then when --log-bin is used, creation of " - "a stored function (or trigger) is allowed only to users having the SUPER privilege " - "and only if this stored function (trigger) may not break binary logging." + "a stored function (or trigger) is allowed only to users having the SUPER " + "privilege, and only if this stored function (trigger) may not break " + "binary logging." "Note that if ALL connections to this server ALWAYS use row-based binary " "logging, the security issues do not exist and the binary logging cannot " "break, so you can safely set this to 1." @@ -6064,7 +6065,7 @@ each time the SQL thread starts.", REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"log-tc", OPT_LOG_TC, "Path to transaction coordinator log (used for transactions that affect " - "more than one storage engine, when binary log is disabled)", + "more than one storage engine, when binary log is disabled).", (uchar**) &opt_tc_log_file, (uchar**) &opt_tc_log_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_MMAP @@ -6088,7 +6089,9 @@ log and this option justs turns on --log-bin instead.", (uchar**) &max_system_variables.low_priority_updates, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"master-connect-retry", OPT_MASTER_CONNECT_RETRY, - "The number of seconds the slave thread will sleep before retrying to connect to the master in case the master goes down or the connection is lost.", + "The number of seconds the slave thread will sleep before retrying to " + "connect to the master, in case the master goes down or the connection " + "is lost.", (uchar**) &master_connect_retry, (uchar**) &master_connect_retry, 0, GET_UINT, REQUIRED_ARG, 60, 0, 0, 0, 0, 0}, {"master-host", OPT_MASTER_HOST, @@ -6101,7 +6104,9 @@ thread is in the master's binlogs.", (uchar**) &master_info_file, (uchar**) &master_info_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"master-password", OPT_MASTER_PASSWORD, - "The password the slave thread will authenticate with when connecting to the master. If not set, an empty password is assumed.The value in master.info will take precedence if it can be read.", + "The password the slave thread will authenticate with when connecting to " + "the master. If not set, an empty password is assumed. The value in " + "master.info will take precedence if it can be read.", (uchar**)&master_password, (uchar**)&master_password, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"master-port", OPT_MASTER_PORT, @@ -6125,8 +6130,8 @@ thread is in the master's binlogs.", (uchar**) &master_ssl_capath, (uchar**) &master_ssl_capath, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-cert", OPT_MASTER_SSL_CERT, - "Master SSL certificate file name. Only applies if you have enabled \ -master-ssl", + "Master SSL certificate file name. Only applies if you have enabled " + "master-ssl.", (uchar**) &master_ssl_cert, (uchar**) &master_ssl_cert, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-cipher", OPT_MASTER_SSL_CIPHER, @@ -6193,14 +6198,14 @@ master-ssl", #ifdef HAVE_NDB_BINLOG {"ndb-report-thresh-binlog-epoch-slip", OPT_NDB_REPORT_THRESH_BINLOG_EPOCH_SLIP, "Threshold on number of epochs to be behind before reporting binlog status. " - "E.g. 3 means that if the difference between what epoch has been received " + "E.g., 3 means that if the difference between what epoch has been received " "from the storage nodes and what has been applied to the binlog is 3 or more, " "a status message will be sent to the cluster log.", (uchar**) &ndb_report_thresh_binlog_epoch_slip, (uchar**) &ndb_report_thresh_binlog_epoch_slip, 0, GET_ULONG, REQUIRED_ARG, 3, 0, 256, 0, 0, 0}, {"ndb-report-thresh-binlog-mem-usage", OPT_NDB_REPORT_THRESH_BINLOG_MEM_USAGE, - "Threshold on percentage of free memory before reporting binlog status. E.g. " + "Threshold on percentage of free memory before reporting binlog status. E.g., " "10 means that if amount of available memory for receiving binlog data from " "the storage nodes goes below 10%, " "a status message will be sent to the cluster log.", @@ -6215,7 +6220,7 @@ master-ssl", (uchar**) &global_system_variables.ndb_use_exact_count, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, {"ndb_use_exact_count", OPT_NDB_USE_EXACT_COUNT, - "same as --ndb-use-exact-count.", + "Same as --ndb-use-exact-count.", (uchar**) &global_system_variables.ndb_use_exact_count, (uchar**) &global_system_variables.ndb_use_exact_count, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, @@ -6226,7 +6231,7 @@ master-ssl", (uchar**) &global_system_variables.ndb_use_transactions, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, {"ndb_use_transactions", OPT_NDB_USE_TRANSACTIONS, - "same as --ndb-use-transactions.", + "Same as --ndb-use-transactions.", (uchar**) &global_system_variables.ndb_use_transactions, (uchar**) &global_system_variables.ndb_use_transactions, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, @@ -6241,7 +6246,9 @@ master-ssl", (uchar**) &opt_ndb_optimized_node_selection, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, { "ndb-cache-check-time", OPT_NDB_CACHE_CHECK_TIME, - "A dedicated thread is created to, at the given millisecons interval, invalidate the query cache if another MySQL server in the cluster has changed the data in the database.", + "A dedicated thread is created to, at the given milliseconds interval, " + "invalidate the query cache if another MySQL server in the cluster has " + "changed the data in the database.", (uchar**) &opt_ndb_cache_check_time, (uchar**) &opt_ndb_cache_check_time, 0, GET_ULONG, REQUIRED_ARG, 0, 0, LONG_TIMEOUT, 0, 1, 0}, {"ndb-index-stat-enable", OPT_NDB_INDEX_STAT_ENABLE, @@ -6256,12 +6263,13 @@ master-ssl", (uchar**) &global_system_variables.ndb_use_copying_alter_table, (uchar**) &global_system_variables.ndb_use_copying_alter_table, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"new", 'n', "Use very new possible 'unsafe' functions.", + {"new", 'n', "Use very new, possibly 'unsafe', functions.", (uchar**) &global_system_variables.new_mode, (uchar**) &max_system_variables.new_mode, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef NOT_YET - {"no-mix-table-types", OPT_NO_MIX_TYPE, "Don't allow commands with uses two different table types.", + {"no-mix-table-types", OPT_NO_MIX_TYPE, + "Don't allow commands that use two different table types.", (uchar**) &opt_no_mix_types, (uchar**) &opt_no_mix_types, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif @@ -6275,10 +6283,12 @@ master-ssl", (uchar**) &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"one-thread", OPT_ONE_THREAD, - "(deprecated): Only use one thread (for debugging under Linux). Use thread-handling=no-threads instead", + "(Deprecated): Only use one thread (for debugging under Linux). Use " + "thread-handling=no-threads instead.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"old-style-user-limits", OPT_OLD_STYLE_USER_LIMITS, - "Enable old-style user limits (before 5.0.3 user resources were counted per each user+host vs. per account)", + "Enable old-style user limits (before 5.0.3, user resources were counted " + "per each user+host vs. per account).", (uchar**) &opt_old_style_user_limits, (uchar**) &opt_old_style_user_limits, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"pid-file", OPT_PID_FILE, "Pid file used by safe_mysqld.", @@ -6294,10 +6304,10 @@ master-ssl", (uchar**) &mysqld_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"port-open-timeout", OPT_PORT_OPEN_TIMEOUT, "Maximum time in seconds to wait for the port to become free. " - "(Default: no wait)", (uchar**) &mysqld_port_timeout, + "(Default: No wait).", (uchar**) &mysqld_port_timeout, (uchar**) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) - {"profiling_history_size", OPT_PROFILING, "Limit of query profiling memory", + {"profiling_history_size", OPT_PROFILING, "Limit of query profiling memory.", (uchar**) &global_system_variables.profiling_history_size, (uchar**) &max_system_variables.profiling_history_size, 0, GET_ULONG, REQUIRED_ARG, 15, 0, 100, 0, 0, 0}, @@ -6367,7 +6377,7 @@ Can't be set to 1 if --log-slave-updates is used.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef TO_BE_DELETED {"safe-show-database", OPT_SAFE_SHOW_DB, - "Deprecated option; use GRANT SHOW DATABASES instead...", + "Deprecated option; use GRANT SHOW DATABASES instead.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"safe-user-create", OPT_SAFE_USER_CREATE, @@ -6381,7 +6391,7 @@ Can't be set to 1 if --log-slave-updates is used.", (uchar**) &opt_secure_auth, (uchar**) &opt_secure_auth, 0, GET_BOOL, NO_ARG, my_bool(0), 0, 0, 0, 0, 0}, {"secure-file-priv", OPT_SECURE_FILE_PRIV, - "Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files within specified directory", + "Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files within specified directory.", (uchar**) &opt_secure_file_priv, (uchar**) &opt_secure_file_priv, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"server-id", OPT_SERVER_ID, @@ -6389,7 +6399,8 @@ Can't be set to 1 if --log-slave-updates is used.", (uchar**) &server_id, (uchar**) &server_id, 0, GET_ULONG, REQUIRED_ARG, 0, 0, UINT_MAX32, 0, 0, 0}, {"set-variable", 'O', - "Change the value of a variable. Please note that this option is deprecated;you can set variables directly with --variable-name=value.", + "Change the value of a variable. Please note that this option is deprecated; " + "you can set variables directly with --variable-name=value.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_SMEM {"shared-memory", OPT_ENABLE_SHARED_MEMORY, @@ -6402,12 +6413,12 @@ Can't be set to 1 if --log-slave-updates is used.", 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"show-slave-auth-info", OPT_SHOW_SLAVE_AUTH_INFO, - "Show user and password in SHOW SLAVE HOSTS on this master", + "Show user and password in SHOW SLAVE HOSTS on this master.", (uchar**) &opt_show_slave_auth_info, (uchar**) &opt_show_slave_auth_info, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef DISABLE_GRANT_OPTIONS {"skip-grant-tables", OPT_SKIP_GRANT, - "Start without grant tables. This gives all users FULL ACCESS to all tables!", + "Start without grant tables. This gives all users FULL ACCESS to all tables.", (uchar**) &opt_noacl, (uchar**) &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif @@ -6422,7 +6433,7 @@ Can't be set to 1 if --log-slave-updates is used.", {"skip-networking", OPT_SKIP_NETWORKING, "Don't allow connection with TCP/IP.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-new", OPT_SKIP_NEW, "Don't use new, possible wrong routines.", + {"skip-new", OPT_SKIP_NEW, "Don't use new, possibly wrong routines.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef DBUG_OFF #ifdef SAFEMALLOC @@ -6440,7 +6451,7 @@ Can't be set to 1 if --log-slave-updates is used.", {"skip-stack-trace", OPT_SKIP_STACK_TRACE, "Don't print a stack trace on failure.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. Deprecated option. Use --skip-symbolic-links instead.", + {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. Deprecated option. Use --skip-symbolic-links instead.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-thread-priority", OPT_SKIP_PRIOR, "Don't give threads different priorities. Deprecated option.", 0, 0, 0, GET_NO_ARG, NO_ARG, @@ -6455,11 +6466,11 @@ replicating a LOAD DATA INFILE command.", "Tells the slave thread to continue replication when a query event returns an error from the provided list.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"slave-exec-mode", OPT_SLAVE_EXEC_MODE, - "Modes for how replication events should be executed. Legal values are STRICT (default) and IDEMPOTENT. In IDEMPOTENT mode, replication will not stop for operations that are idempotent. In STRICT mode, replication will stop on any unexpected difference between the master and the slave.", + "Modes for how replication events should be executed. Legal values are STRICT (default) and IDEMPOTENT. In IDEMPOTENT mode, replication will not stop for operations that are idempotent. In STRICT mode, replication will stop on any unexpected difference between the master and the slave.", (uchar**) &slave_exec_mode_str, (uchar**) &slave_exec_mode_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"slow-query-log", OPT_SLOW_LOG, - "Enable|disable slow query log", (uchar**) &opt_slow_log, + "Enable/disable slow query log.", (uchar**) &opt_slow_log, (uchar**) &opt_slow_log, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"socket", OPT_SOCKET, "Socket file to use for connection.", (uchar**) &mysqld_unix_port, (uchar**) &mysqld_unix_port, 0, GET_STR, @@ -6521,7 +6532,7 @@ log and this option does nothing anymore.", 0, 0, 0, 0, 0}, {"timed_mutexes", OPT_TIMED_MUTEXES, - "Specify whether to time mutexes (only InnoDB mutexes are currently supported)", + "Specify whether to time mutexes (only InnoDB mutexes are currently supported).", (uchar**) &timed_mutexes, (uchar**) &timed_mutexes, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"tmpdir", 't', @@ -6542,7 +6553,7 @@ log and this option does nothing anymore.", IF_PURIFY(0,1), 0, 0, 0, 0, 0}, {"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"verbose", 'v', "Used with --help option for detailed help", + {"verbose", 'v', "Used with --help option for detailed help.", (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, @@ -6560,7 +6571,7 @@ log and this option does nothing anymore.", (uchar**) &binlog_cache_size, (uchar**) &binlog_cache_size, 0, GET_ULONG, REQUIRED_ARG, 32*1024L, IO_SIZE, ULONG_MAX, 0, IO_SIZE, 0}, {"bulk_insert_buffer_size", OPT_BULK_INSERT_BUFFER_SIZE, - "Size of tree cache used in bulk insert optimisation. Note that this is a limit per thread!", + "Size of tree cache used in bulk insert optimization. Note that this is a limit per thread.", (uchar**) &global_system_variables.bulk_insert_buff_size, (uchar**) &max_system_variables.bulk_insert_buff_size, 0, GET_ULONG, REQUIRED_ARG, 8192*1024, 0, ULONG_MAX, 0, 1, 0}, @@ -6569,7 +6580,7 @@ log and this option does nothing anymore.", (uchar**) &connect_timeout, (uchar**) &connect_timeout, 0, GET_ULONG, REQUIRED_ARG, CONNECT_TIMEOUT, 2, LONG_TIMEOUT, 0, 1, 0 }, { "date_format", OPT_DATE_FORMAT, - "The DATE format (For future).", + "The DATE format (for future).", (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_DATE], (uchar**) &opt_date_time_formats[MYSQL_TIMESTAMP_DATE], 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -6611,7 +6622,7 @@ log and this option does nothing anymore.", (uchar**) &flush_time, (uchar**) &flush_time, 0, GET_ULONG, REQUIRED_ARG, FLUSH_TIME, 0, LONG_TIMEOUT, 0, 1, 0}, { "ft_boolean_syntax", OPT_FT_BOOLEAN_SYNTAX, - "List of operators for MATCH ... AGAINST ( ... IN BOOLEAN MODE)", + "List of operators for MATCH ... AGAINST ( ... IN BOOLEAN MODE).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { "ft_max_word_len", OPT_FT_MAX_WORD_LEN, @@ -6623,7 +6634,7 @@ log and this option does nothing anymore.", (uchar**) &ft_min_word_len, (uchar**) &ft_min_word_len, 0, GET_ULONG, REQUIRED_ARG, 4, 1, HA_FT_MAXCHARLEN, 0, 1, 0}, { "ft_query_expansion_limit", OPT_FT_QUERY_EXPANSION_LIMIT, - "Number of best matches to use for query expansion", + "Number of best matches to use for query expansion.", (uchar**) &ft_query_expansion_limit, (uchar**) &ft_query_expansion_limit, 0, GET_ULONG, REQUIRED_ARG, 20, 0, 1000, 0, 1, 0}, { "ft_stopword_file", OPT_FT_STOPWORD_FILE, @@ -6631,7 +6642,7 @@ log and this option does nothing anymore.", (uchar**) &ft_stopword_file, (uchar**) &ft_stopword_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { "group_concat_max_len", OPT_GROUP_CONCAT_MAX_LEN, - "The maximum length of the result of function group_concat.", + "The maximum length of the result of function group_concat.", (uchar**) &global_system_variables.group_concat_max_len, (uchar**) &max_system_variables.group_concat_max_len, 0, GET_ULONG, REQUIRED_ARG, 1024, 4, ULONG_MAX, 0, 1, 0}, @@ -6659,30 +6670,36 @@ log and this option does nothing anymore.", REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, SIZE_T_MAX, MALLOC_OVERHEAD, IO_SIZE, 0}, {"key_cache_age_threshold", OPT_KEY_CACHE_AGE_THRESHOLD, - "This characterizes the number of hits a hot block has to be untouched until it is considered aged enough to be downgraded to a warm block. This specifies the percentage ratio of that number of hits to the total number of blocks in key cache", + "This characterizes the number of hits a hot block has to be untouched " + "until it is considered aged enough to be downgraded to a warm block. " + "This specifies the percentage ratio of that number of hits to the total " + "number of blocks in key cache.", (uchar**) &dflt_key_cache_var.param_age_threshold, (uchar**) 0, 0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, 300, 100, ULONG_MAX, 0, 100, 0}, {"key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, - "The default size of key cache blocks", + "The default size of key cache blocks.", (uchar**) &dflt_key_cache_var.param_block_size, (uchar**) 0, 0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, KEY_CACHE_BLOCK_SIZE, 512, 1024 * 16, 0, 512, 0}, {"key_cache_division_limit", OPT_KEY_CACHE_DIVISION_LIMIT, - "The minimum percentage of warm blocks in key cache", + "The minimum percentage of warm blocks in key cache.", (uchar**) &dflt_key_cache_var.param_division_limit, (uchar**) 0, 0, (GET_ULONG | GET_ASK_ADDR) , REQUIRED_ARG, 100, 1, 100, 0, 1, 0}, {"long_query_time", OPT_LONG_QUERY_TIME, - "Log all queries that have taken more than long_query_time seconds to execute to file. " - "The argument will be treated as a decimal value with microsecond precission.", + "Log all queries that have taken more than long_query_time seconds to " + "execute. The argument will be treated as a decimal value with " + "microsecond precision.", (uchar**) &long_query_time, (uchar**) &long_query_time, 0, GET_DOUBLE, REQUIRED_ARG, 10, 0, LONG_TIMEOUT, 0, 0, 0}, {"lower_case_table_names", OPT_LOWER_CASE_TABLE_NAMES, - "If set to 1 table names are stored in lowercase on disk and table names will be case-insensitive. Should be set to 2 if you are using a case insensitive file system", + "If set to 1, table names are stored in lowercase on disk and table names " + "will be case-insensitive. Should be set to 2 if you are using a case-" + "insensitive file system.", (uchar**) &lower_case_table_names, (uchar**) &lower_case_table_names, 0, GET_UINT, OPT_ARG, #ifdef FN_NO_CASE_SENCE @@ -6692,7 +6709,7 @@ log and this option does nothing anymore.", #endif , 0, 2, 0, 1, 0}, {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, - "Max packetlength to send/receive from to server.", + "The maximum packet length to send to or receive from server.", (uchar**) &global_system_variables.max_allowed_packet, (uchar**) &max_system_variables.max_allowed_packet, 0, GET_ULONG, REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0}, @@ -6751,7 +6768,7 @@ The minimum value for this variable is 4096.", (uchar**) &max_relay_log_size, (uchar**) &max_relay_log_size, 0, GET_ULONG, REQUIRED_ARG, 0L, 0L, 1024*1024L*1024L, 0, IO_SIZE, 0}, { "max_seeks_for_key", OPT_MAX_SEEKS_FOR_KEY, - "Limit assumed max number of seeks when looking up rows based on a key", + "Limit assumed max number of seeks when looking up rows based on a key.", (uchar**) &global_system_variables.max_seeks_for_key, (uchar**) &max_system_variables.max_seeks_for_key, 0, GET_ULONG, REQUIRED_ARG, ULONG_MAX, 1, ULONG_MAX, 0, 1, 0 }, @@ -6827,7 +6844,7 @@ The minimum value for this variable is 4096.", (uchar**) &max_system_variables.myisam_sort_buff_size, 0, GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0}, {"myisam_use_mmap", OPT_MYISAM_USE_MMAP, - "Use memory mapping for reading and writing MyISAM tables", + "Use memory mapping for reading and writing MyISAM tables.", (uchar**) &opt_myisam_use_mmap, (uchar**) &opt_myisam_use_mmap, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -6853,7 +6870,8 @@ The minimum value for this variable is 4096.", (uchar**) &max_system_variables.net_retry_count,0, GET_ULONG, REQUIRED_ARG, MYSQLD_NET_RETRY_COUNT, 1, ULONG_MAX, 0, 1, 0}, {"net_write_timeout", OPT_NET_WRITE_TIMEOUT, - "Number of seconds to wait for a block to be written to a connection before aborting the write.", + "Number of seconds to wait for a block to be written to a connection before " + "aborting the write.", (uchar**) &global_system_variables.net_write_timeout, (uchar**) &max_system_variables.net_write_timeout, 0, GET_ULONG, REQUIRED_ARG, NET_WRITE_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, @@ -6893,12 +6911,12 @@ The minimum value for this variable is 4096.", (uchar**) &opt_plugin_load, (uchar**) &opt_plugin_load, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"preload_buffer_size", OPT_PRELOAD_BUFFER_SIZE, - "The size of the buffer that is allocated when preloading indexes", + "The size of the buffer that is allocated when preloading indexes.", (uchar**) &global_system_variables.preload_buff_size, (uchar**) &max_system_variables.preload_buff_size, 0, GET_ULONG, REQUIRED_ARG, 32*1024L, 1024, 1024*1024*1024L, 0, 1, 0}, {"query_alloc_block_size", OPT_QUERY_ALLOC_BLOCK_SIZE, - "Allocation block size for query parsing and execution", + "Allocation block size for query parsing and execution.", (uchar**) &global_system_variables.query_alloc_block_size, (uchar**) &max_system_variables.query_alloc_block_size, 0, GET_ULONG, REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ULONG_MAX, 0, 1024, 0}, @@ -6908,7 +6926,8 @@ The minimum value for this variable is 4096.", (uchar**) &query_cache_limit, (uchar**) &query_cache_limit, 0, GET_ULONG, REQUIRED_ARG, 1024*1024L, 0, ULONG_MAX, 0, 1, 0}, {"query_cache_min_res_unit", OPT_QUERY_CACHE_MIN_RES_UNIT, - "minimal size of unit in wich space for results is allocated (last unit will be trimed after writing all result data.", + "Minimal size of unit in which space for results is allocated (last unit " + "will be trimmed after writing all result data).", (uchar**) &query_cache_min_res_unit, (uchar**) &query_cache_min_res_unit, 0, GET_ULONG, REQUIRED_ARG, QUERY_CACHE_MIN_RESULT_DATA_SIZE, 0, ULONG_MAX, 0, 1, 0}, @@ -6924,19 +6943,19 @@ The minimum value for this variable is 4096.", (uchar**) &max_system_variables.query_cache_type, 0, GET_ULONG, REQUIRED_ARG, 1, 0, 2, 0, 1, 0}, {"query_cache_wlock_invalidate", OPT_QUERY_CACHE_WLOCK_INVALIDATE, - "Invalidate queries in query cache on LOCK for write", + "Invalidate queries in query cache on LOCK for write.", (uchar**) &global_system_variables.query_cache_wlock_invalidate, (uchar**) &max_system_variables.query_cache_wlock_invalidate, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, #endif /*HAVE_QUERY_CACHE*/ {"query_prealloc_size", OPT_QUERY_PREALLOC_SIZE, - "Persistent buffer for query parsing and execution", + "Persistent buffer for query parsing and execution.", (uchar**) &global_system_variables.query_prealloc_size, (uchar**) &max_system_variables.query_prealloc_size, 0, GET_ULONG, REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, QUERY_ALLOC_PREALLOC_SIZE, ULONG_MAX, 0, 1024, 0}, {"range_alloc_block_size", OPT_RANGE_ALLOC_BLOCK_SIZE, - "Allocation block size for storing ranges during optimization", + "Allocation block size for storing ranges during optimization.", (uchar**) &global_system_variables.range_alloc_block_size, (uchar**) &max_system_variables.range_alloc_block_size, 0, GET_ULONG, REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, RANGE_ALLOC_BLOCK_SIZE, ULONG_MAX, @@ -6948,12 +6967,15 @@ The minimum value for this variable is 4096.", 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, INT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0}, {"read_only", OPT_READONLY, - "Make all non-temporary tables read-only, with the exception for replication (slave) threads and users with the SUPER privilege", + "Make all non-temporary tables read-only, with the exception of replication " + "(slave) threads and users with the SUPER privilege.", (uchar**) &opt_readonly, (uchar**) &opt_readonly, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, {"read_rnd_buffer_size", OPT_RECORD_RND_BUFFER, - "When reading rows in sorted order after a sort, the rows are read through this buffer to avoid a disk seeks. If not set, then it's set to the value of record_buffer.", + "When reading rows in sorted order after a sort, the rows are read through " + "this buffer to avoid disk seeks. If not set, then it's set to the value of " + "record_buffer.", (uchar**) &global_system_variables.read_rnd_buff_size, (uchar**) &max_system_variables.read_rnd_buff_size, 0, GET_ULONG, REQUIRED_ARG, 256*1024L, IO_SIZE*2+MALLOC_OVERHEAD, @@ -7036,7 +7058,8 @@ The minimum value for this variable is 4096.", DEFAULT_CONCURRENCY, 1, 512, 0, 1, 0}, #if HAVE_POOL_OF_THREADS == 1 {"thread_pool_size", OPT_THREAD_CACHE_SIZE, - "How many threads we should create to handle query requests in case of 'thread_handling=pool-of-threads'", + "How many threads we should create to handle query requests in case of " + "'thread_handling=pool-of-threads'.", (uchar**) &thread_pool_size, (uchar**) &thread_pool_size, 0, GET_ULONG, REQUIRED_ARG, 20, 1, 16384, 0, 1, 0}, #endif @@ -7056,18 +7079,18 @@ The minimum value for this variable is 4096.", (uchar**) &max_system_variables.tmp_table_size, 0, GET_ULL, REQUIRED_ARG, 16*1024*1024L, 1024, MAX_MEM_TABLE_SIZE, 0, 1, 0}, {"transaction_alloc_block_size", OPT_TRANS_ALLOC_BLOCK_SIZE, - "Allocation block size for transactions to be stored in binary log", + "Allocation block size for transactions to be stored in binary log.", (uchar**) &global_system_variables.trans_alloc_block_size, (uchar**) &max_system_variables.trans_alloc_block_size, 0, GET_ULONG, REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ULONG_MAX, 0, 1024, 0}, {"transaction_prealloc_size", OPT_TRANS_PREALLOC_SIZE, - "Persistent buffer for transactions to be stored in binary log", + "Persistent buffer for transactions to be stored in binary log.", (uchar**) &global_system_variables.trans_prealloc_size, (uchar**) &max_system_variables.trans_prealloc_size, 0, GET_ULONG, REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ULONG_MAX, 0, 1024, 0}, {"thread_handling", OPT_THREAD_HANDLING, - "Define threads usage for handling queries: " - "one-thread-per-connection or no-threads", 0, 0, + "Define threads usage for handling queries: " + "one-thread-per-connection or no-threads.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"updatable_views_with_limit", OPT_UPDATABLE_VIEWS_WITH_LIMIT, "1 = YES = Don't issue an error message (warning only) if a VIEW without presence of a key of the underlying table is used in queries with a LIMIT clause for updating. 0 = NO = Prohibit update of a VIEW, which does not contain a key of the underlying table and the query uses a LIMIT clause (usually get from GUI tools).", @@ -7081,7 +7104,11 @@ The minimum value for this variable is 4096.", REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT), 0, 1, 0}, {"binlog-direct-non-transactional-updates", OPT_BINLOG_DIRECT_NON_TRANS_UPDATE, - "Causes updates to non-transactional engines using statement format to be written directly to binary log. Before using this option make sure that there are no dependencies between transactional and non-transactional tables such as in the statement INSERT INTO t_myisam SELECT * FROM t_innodb; otherwise, slaves may diverge from the master.", + "Causes updates to non-transactional engines using statement format to be " + "written directly to binary log. Before using this option, make sure that " + "there are no dependencies between transactional and non-transactional " + "tables such as in the statement INSERT INTO t_myisam SELECT * FROM " + "t_innodb; otherwise, slaves may diverge from the master.", (uchar**) &global_system_variables.binlog_direct_non_trans_update, (uchar**) &max_system_variables.binlog_direct_non_trans_update, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} @@ -7597,27 +7624,27 @@ static void usage(void) default_collation_name= (char*) default_charset_info->name; print_version(); puts("\ -Copyright (C) 2000-2008 MySQL AB, by Monty and others\n\ +Copyright (C) 2000-2008 MySQL AB, by Monty and others.\n\ Copyright (C) 2008 Sun Microsystems, Inc.\n\ This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ and you are welcome to modify and redistribute it under the GPL license\n\n\ -Starts the MySQL database server\n"); +Starts the MySQL database server.\n"); printf("Usage: %s [OPTIONS]\n", my_progname); if (!opt_verbose) - puts("\nFor more help options (several pages), use mysqld --verbose --help"); + puts("\nFor more help options (several pages), use mysqld --verbose --help."); else { #ifdef __WIN__ puts("NT and Win32 specific options:\n\ - --install Install the default service (NT)\n\ - --install-manual Install the default service started manually (NT)\n\ - --install service_name Install an optional service (NT)\n\ - --install-manual service_name Install an optional service started manually (NT)\n\ - --remove Remove the default service from the service list (NT)\n\ - --remove service_name Remove the service_name from the service list (NT)\n\ - --enable-named-pipe Only to be used for the default server (NT)\n\ - --standalone Dummy option to start as a standalone server (NT)\ + --install Install the default service (NT).\n\ + --install-manual Install the default service started manually (NT).\n\ + --install service_name Install an optional service (NT).\n\ + --install-manual service_name Install an optional service started manually (NT).\n\ + --remove Remove the default service from the service list (NT).\n\ + --remove service_name Remove the service_name from the service list (NT).\n\ + --enable-named-pipe Only to be used for the default server (NT).\n\ + --standalone Dummy option to start as a standalone server (NT).\ "); puts(""); #endif -- cgit v1.2.1 From a89d88dc0a5db71cb1c748e5fc7b6a570cc5c2ee Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 2 Feb 2010 18:30:23 +0200 Subject: Bug #45989 take 2 : memory leak after explain encounters an error in the query. Fixes a leak after materializing a GROUP BY subquery to a temp table when the subquery has a blob column in the SELECT list. Fixed by correctly destructing temporary buffers for re-usable queries --- sql/sql_select.cc | 12 ++++++++++++ sql/sql_select.h | 20 +++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index da85ca27339..0a3c61d2b97 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2313,6 +2313,12 @@ JOIN::destroy() tab->cleanup(); } tmp_join->tmp_join= 0; + /* + We need to clean up tmp_table_param for reusable JOINs (having non-zero + and different from self tmp_join) because it's not being cleaned up + anywhere else (as we need to keep the join is reusable). + */ + tmp_table_param.cleanup(); tmp_table_param.copy_field= 0; DBUG_RETURN(tmp_join->destroy()); } @@ -5838,6 +5844,12 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table) const_table_map= 0; tmp_table_param.field_count= tmp_table_param.sum_func_count= tmp_table_param.func_count= 0; + /* + We need to destruct the copy_field (allocated in create_tmp_table()) + before setting it to 0 if the join is not "reusable". + */ + if (!tmp_join || tmp_join != this) + tmp_table_param.cleanup(); tmp_table_param.copy_field= tmp_table_param.copy_field_end=0; first_record= sort_and_group=0; send_records= (ha_rows) 0; diff --git a/sql/sql_select.h b/sql/sql_select.h index dd99d358bac..bfff0a0ffa2 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -354,7 +354,25 @@ public: */ bool no_const_tables; - JOIN *tmp_join; ///< copy of this JOIN to be used with temporary tables + /** + Copy of this JOIN to be used with temporary tables. + + tmp_join is used when the JOIN needs to be "reusable" (e.g. in a subquery + that gets re-executed several times) and we know will use temporary tables + for materialization. The materialization to a temporary table overwrites the + JOIN structure to point to the temporary table after the materialization is + done. This is where tmp_join is used : it's a copy of the JOIN before the + materialization and is used in restoring before re-execution by overwriting + the current JOIN structure with the saved copy. + Because of this we should pay extra care of not freeing up helper structures + that are referenced by the original contents of the JOIN. We can check for + this by making sure the "current" join is not the temporary copy, e.g. + !tmp_join || tmp_join != join + + We should free these sub-structures at JOIN::destroy() if the "current" join + has a copy is not that copy. + */ + JOIN *tmp_join; ROLLUP rollup; ///< Used with rollup bool select_distinct; ///< Set if SELECT DISTINCT -- cgit v1.2.1 From 3c9bfe8334fe2628d29b1aad39d9ad4f5e723d62 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 4 Feb 2010 18:51:55 +0200 Subject: Addendum to the fix for bug #45989 Need to make sure the tmp join doesn't point to the structure already freed by the cleanup() for the "base" join, as this can lead to double free, because sometimes both tmp_join and join point to the same tmp_table_params.copy_field array. --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0a3c61d2b97..9136b2e57e3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2319,7 +2319,7 @@ JOIN::destroy() anywhere else (as we need to keep the join is reusable). */ tmp_table_param.cleanup(); - tmp_table_param.copy_field= 0; + tmp_table_param.copy_field= tmp_join->tmp_table_param.copy_field= 0; DBUG_RETURN(tmp_join->destroy()); } cond_equal= 0; -- cgit v1.2.1 From 2be07c70947924c9829ad58dd1ee9d1f4228c401 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 5 Feb 2010 13:39:46 +0400 Subject: Bug#47736 killing a select from a view when the view is processing a function, asserts hide_view_error() does not take into account that thread query may be killed. Added a check for thd->killed. Addon: backported bug32140 fix from 6.0 mysql-test/r/sp_notembedded.result: test case mysql-test/t/sp_notembedded.test: test case sql/sp.cc: backported bug32140 fix from 6.0 sql/table.cc: Added a check for thd->killed. --- sql/sp.cc | 4 ++++ sql/table.cc | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sp.cc b/sql/sp.cc index f0508142557..ef69edb96c6 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1898,6 +1898,10 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, ret= SP_OK; break; default: + /* Query might have been killed, don't set error. */ + if (thd->killed) + break; + /* Any error when loading an existing routine is either some problem with the mysql.proc table, or a parse error because the contents diff --git a/sql/table.cc b/sql/table.cc index c06ecf99926..8a8228b9954 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3365,7 +3365,7 @@ 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()) + if (thd->killed || thd->get_internal_handler()) return; /* Hide "Unknown column" or "Unknown function" error */ DBUG_ASSERT(thd->is_error()); -- cgit v1.2.1 From 6b8ec684c794455f442d45e2086dd3161e9bcde1 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 23 Dec 2009 12:45:18 +0200 Subject: Bug #39022: Mysql randomly crashing in lock_sec_rec_cons_read_sees flush_cached_records() was not correctly checking for errors after calling Item::val_xxx() methods. The expressions may contain subqueries or stored procedures that cause errors that should stop the statement. Fixed by correctly checking for errors and propagating them up the call stack. --- sql/sql_select.cc | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9136b2e57e3..bdd139edafc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11521,21 +11521,45 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) return NESTED_LOOP_KILLED; // Aborted by user /* purecov: inspected */ } SQL_SELECT *select=join_tab->select; - if (rc == NESTED_LOOP_OK && - (!join_tab->cache.select || !join_tab->cache.select->skip_record())) + if (rc == NESTED_LOOP_OK) { - uint i; - reset_cache_read(&join_tab->cache); - for (i=(join_tab->cache.records- (skip_last ? 1 : 0)) ; i-- > 0 ;) + bool consider_record= !join_tab->cache.select || + !join_tab->cache.select->skip_record(); + + /* + Check for error: skip_record() can execute code by calling + Item_subselect::val_*. We need to check for errors (if any) + after such call. + */ + if (join->thd->is_error()) + { + reset_cache_write(&join_tab->cache); + return NESTED_LOOP_ERROR; + } + + if (consider_record) { - read_cached_record(join_tab); - if (!select || !select->skip_record()) + uint i; + reset_cache_read(&join_tab->cache); + for (i=(join_tab->cache.records- (skip_last ? 1 : 0)) ; i-- > 0 ;) { - rc= (join_tab->next_select)(join,join_tab+1,0); - if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS) + read_cached_record(join_tab); + if (!select || !select->skip_record()) { - reset_cache_write(&join_tab->cache); - return rc; + /* + Check for error: skip_record() can execute code by calling + Item_subselect::val_*. We need to check for errors (if any) + after such call. + */ + if (join->thd->is_error()) + rc= NESTED_LOOP_ERROR; + else + rc= (join_tab->next_select)(join,join_tab+1,0); + if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS) + { + reset_cache_write(&join_tab->cache); + return rc; + } } } } -- cgit v1.2.1 From 630fa243c9a459526e225acc19fee30f4676a505 Mon Sep 17 00:00:00 2001 From: Martin Hansson Date: Wed, 10 Feb 2010 15:37:34 +0100 Subject: Bug#49534: multitable IGNORE update with sql_safe_updates error causes debug assertion The IGNORE option of the multiple-table UPDATE command was not intended to suppress errors caused by the sql_safe_updates mode. This flag will raise an error if the execution of UPDATE does not use a key for row retrieval, and should continue do so regardless of the IGNORE option. However the implementation of IGNORE does not support exceptions to the rule; it always converts errors to warnings and cannot be extended. The Internal_error_handler interface offers the infrastructure to handle individual errors, making sure that the error raised by sql_safe_updates is not silenced. Fixed by implementing an Internal_error_handler and using it for UPDATE IGNORE commands. --- sql/sql_class.cc | 4 ++- sql/sql_class.h | 2 +- sql/sql_update.cc | 87 ++++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 81 insertions(+), 12 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7b37a3f6e93..b22aa41b40a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -740,10 +740,12 @@ bool THD::handle_error(uint sql_errno, const char *message, } -void THD::pop_internal_handler() +Internal_error_handler *THD::pop_internal_handler() { DBUG_ASSERT(m_internal_handler != NULL); + Internal_error_handler *popped_handler= m_internal_handler; m_internal_handler= m_internal_handler->m_prev_internal_handler; + return popped_handler; } extern "C" diff --git a/sql/sql_class.h b/sql/sql_class.h index 77b4aa6c1d0..032985dc44e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2313,7 +2313,7 @@ public: /** Remove the error handler last pushed. */ - void pop_internal_handler(); + Internal_error_handler *pop_internal_handler(); /** Overloaded to guard query/query_length fields */ virtual void set_statement(Statement *stmt); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 32add8679ef..84610630d62 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1188,6 +1188,56 @@ reopen_tables: } +/** + Implementation of the safe update options during UPDATE IGNORE. This syntax + causes an UPDATE statement to ignore all errors. In safe update mode, + however, we must never ignore the ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE. There + is a special hook in my_message_sql that will otherwise delete all errors + when the IGNORE option is specified. + + In the future, all IGNORE handling should be used with this class and all + traces of the hack outlined below should be removed. + + - The parser detects IGNORE option and sets thd->lex->ignore= 1 + + - In JOIN::optimize, if this is set, then + thd->lex->current_select->no_error gets set. + + - In my_message_sql(), if the flag above is set then any error is + unconditionally converted to a warning. + + We are moving in the direction of using Internal_error_handler subclasses + to do all such error tweaking, please continue this effort if new bugs + appear. + */ +class Safe_dml_handler : public Internal_error_handler { + +private: + bool m_handled_error; + +public: + explicit Safe_dml_handler() : m_handled_error(FALSE) {} + + bool handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd) + { + if (level == MYSQL_ERROR::WARN_LEVEL_ERROR && + sql_errno == ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE) + + { + thd->main_da.set_error_status(thd, sql_errno, message); + m_handled_error= TRUE; + return TRUE; + } + return FALSE; + } + + bool handled_error() { return m_handled_error; } + +}; + /* Setup multi-update handling and call SELECT to do the join */ @@ -1216,18 +1266,35 @@ bool mysql_multi_update(THD *thd, MODE_STRICT_ALL_TABLES)); List total_list; + + Safe_dml_handler handler; + bool using_handler= thd->options & OPTION_SAFE_UPDATES; + if (using_handler) + thd->push_internal_handler(&handler); + res= mysql_select(thd, &select_lex->ref_pointer_array, - table_list, select_lex->with_wild, - total_list, - conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, - (ORDER *)NULL, - options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | - OPTION_SETUP_TABLES_DONE, - result, unit, select_lex); - DBUG_PRINT("info",("res: %d report_error: %d", res, - (int) thd->is_error())); + table_list, select_lex->with_wild, + total_list, + conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, + (ORDER *)NULL, + options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | + OPTION_SETUP_TABLES_DONE, + result, unit, select_lex); + + if (using_handler) + { + Internal_error_handler *top_handler= thd->pop_internal_handler(); + DBUG_ASSERT(&handler == top_handler); + } + + DBUG_PRINT("info",("res: %d report_error: %d", res, (int) thd->is_error())); res|= thd->is_error(); - if (unlikely(res)) + /* + Todo: remove below code and make Safe_dml_handler do error processing + instead. That way we can return the actual error instead of + ER_UNKNOWN_ERROR. + */ + if (unlikely(res) && (!using_handler || !handler.handled_error())) { /* If we had a another error reported earlier then this will be ignored */ result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR)); -- cgit v1.2.1 From f4a16558c81af480d1cd9e09bd3965e598c561ac Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Thu, 11 Feb 2010 21:10:13 +0100 Subject: Bug #47905 stored procedures with conditional statements not being logged to slow query log The problem is that the execution time for a multi-statement stored procedure as a whole may not be accurate, and thus not be entered into the slow query log even if the total time exceeds long_query_time. The reason for this is that THD::utime_after_lock used for time calculation may be reset at the start of each new statement, possibly leaving the total SP execution equal to the time spent executing the last statement in the SP. This patch stores the utime on start of SP execution, and restores it on exit of SP execution. A test is added. mysql-test/suite/sys_vars/r/slow_query_log_func.result: New test results for #47905. mysql-test/suite/sys_vars/t/slow_query_log_func.test: New test case for #47905. sql/sp_head.cc: Save and restore the THD::utime_after_lock on entry and exit of execute_procedure(). --- sql/sp_head.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sql') diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 45cb4eebb09..8a626cabd90 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1848,6 +1848,8 @@ sp_head::execute_procedure(THD *thd, List *args) { bool err_status= FALSE; uint params = m_pcont->context_var_count(); + /* Query start time may be reset in a multi-stmt SP; keep this for later. */ + ulonglong utime_before_sp_exec= thd->utime_after_lock; sp_rcontext *save_spcont, *octx; sp_rcontext *nctx = NULL; bool save_enable_slow_log= false; @@ -2040,6 +2042,7 @@ sp_head::execute_procedure(THD *thd, List *args) delete nctx; thd->spcont= save_spcont; + thd->utime_after_lock= utime_before_sp_exec; DBUG_RETURN(err_status); } -- cgit v1.2.1 From ee66332ce43f5aa05b9957ead4bc8dc9b540695e Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Wed, 27 Jan 2010 11:10:53 -0200 Subject: Bug#47734: Assertion failed: ! is_set() when locking a view with non-existing definer The problem was that a failure to open a view wasn't being properly handled. When opening a view with unknown definer, the open procedure would be treated as successful and would later crash when attempting to lock the view (which wasn't opened to begin with). The solution is to skip further processing when opening a table if it fails with a fatal error. mysql-test/r/view.result: Add test case result for Bug#47734. mysql-test/t/view.test: Add test case for Bug#47734. sql/sql_base.cc: Skip further processing if opening a table failed due to a fatal error (for the statement). --- sql/sql_base.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index a1f34f6a770..06e4b1d3e63 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4591,7 +4591,20 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) safe_to_ignore_table= prelock_handler.safely_trapped_errors(); } else + { tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags); + + /* + Skip further processing if there has been a fatal error while + trying to open a table. For example, this might happen due to + stack shortage, unknown definer in views, etc. + */ + if (!tables->table && thd->is_error()) + { + result= -1; + goto err; + } + } } else DBUG_PRINT("tcache", ("referenced table: '%s'.'%s' 0x%lx", -- cgit v1.2.1 From 63817720b41a9daa5d792d517c58ae29130cc254 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Wed, 10 Feb 2010 16:11:08 -0200 Subject: Bug#48449: hang on show create view after upgrading when view contains function of view SHOW CREATE TABLE on a view (v1) that contains a function whose statement uses another view (v2), could trigger a infinite loop if the view referenced within the function causes a warning to be raised while opening the said view (v2). The problem was a infinite loop over the stack of internal error handlers. The problem would be triggered if the stack contained two or more handlers and the first two handlers didn't handle the raised condition. In this case, the loop variable would always point to the second handler in the stack. The solution is to correct the loop variable assignment so that the loop is able to iterate over all handlers in the stack. mysql-test/r/view.result: Add test case result for Bug#48449. mysql-test/std_data/bug48449.frm: Add a incomplete view definition that causes a warning to be issued. mysql-test/t/view.test: Add test case for Bug#48449 sql/sql_class.cc: Iterate over all handlers in the stack. --- sql/sql_class.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index b22aa41b40a..673fc9b78e6 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -725,15 +725,12 @@ 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) + error_handler= error_handler->m_prev_internal_handler) { if (error_handler->handle_error(sql_errno, message, level, this)) - return TRUE; + return TRUE; } return FALSE; -- cgit v1.2.1 From 32902dad006b68e2bdb855f9c2ea1910a9195c9c Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 11 Feb 2010 19:41:53 +0200 Subject: Addendum to bug #46175 : use and check for the correct error values when converting to a enumerated type. --- sql/item.cc | 2 +- sql/sql_select.h | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index c967a1a0feb..df266434f72 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5157,7 +5157,7 @@ int Item::save_in_field(Field *field, bool no_conversions) field->set_notnull(); error=field->store(nr, unsigned_flag); } - return error ? error : (field->table->in_use->is_error() ? 2 : 0); + return error ? error : (field->table->in_use->is_error() ? 1 : 0); } diff --git a/sql/sql_select.h b/sql/sql_select.h index ef43f9b049c..8d3520bf9c8 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -736,10 +736,11 @@ public: we need to check for errors executing it and react accordingly */ if (!res && table->in_use->is_error()) - res= 2; + res= 1; /* STORE_KEY_FATAL */ dbug_tmp_restore_column_map(table->write_set, old_map); null_key= to_field->is_null() || item->null_value; - return (err != 0 || res > 2 ? STORE_KEY_FATAL : (store_key_result) res); + return ((err != 0 || res < 0 || res > 2) ? STORE_KEY_FATAL : + (store_key_result) res); } }; @@ -775,10 +776,10 @@ protected: we need to check for errors executing it and react accordingly */ if (!err && to_field->table->in_use->is_error()) - err= 2; + err= 1; /* STORE_KEY_FATAL */ } null_key= to_field->is_null() || item->null_value; - return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err); + return ((err < 0 || err > 2) ? STORE_KEY_FATAL : (store_key_result) err); } }; -- cgit v1.2.1 From 46cffd7f5b585527387e2a23d1c3c43d2b14bf2c Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 12 Feb 2010 13:44:20 +0400 Subject: Bug#48294 assertion when creating a view based on some row() construct in select query In case of 'CREATE VIEW' subselect transformation does not happen(see JOIN::prepare). During fix_fields Item_row may call is_null() method for its arugmens which leads to item calculation(wrong subselect in our case as transformation did not happen before). This is_null() call does not make sence for 'CREATE VIEW'. Note: Only Item_row is affected because other items don't call is_null() during fix_fields() for arguments. mysql-test/r/view.result: test case mysql-test/t/view.test: test case sql/item_row.cc: skip is_null() call in case of 'CREATE VIEW' as unnecessary. --- sql/item_row.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_row.cc b/sql/item_row.cc index 28de03bf049..29b37eb2bc0 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -71,7 +71,12 @@ bool Item_row::fix_fields(THD *thd, Item **ref) Item *item= *arg; used_tables_cache |= item->used_tables(); const_item_cache&= item->const_item() && !with_null; - if (const_item_cache) + /* + Some subqueries transformations aren't done in the view_prepare_mode thus + is_null() will fail. So we skip is_null() calculation for CREATE VIEW as + not necessary. + */ + if (const_item_cache && !thd->lex->view_prepare_mode) { if (item->cols() > 1) with_null|= item->null_inside(); -- cgit v1.2.1 From d6ab925c5e10acc72cddbaf910d9aa4bee305c82 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Thu, 28 Jan 2010 12:41:14 -0200 Subject: Bug#50423: Crash on second call of a procedure dropping a trigger The problem was that a DROP TRIGGER statement inside a stored procedure could cause a crash in subsequent invocations. This was due to the addition, on the first execution, of a temporary table reference to the stored procedure query table list. In a subsequent invocation, there would be a attempt to reinitialize the temporary table reference, which by then was already gone. The solution is to backup and reset the query table list each time a trigger needs to be dropped. This ensures that any temp changes to the query table list are discarded. It is safe to do so at this time as drop trigger is restricted from more complicated scenarios (ie, not allowed within stored functions, etc). mysql-test/r/sp-bugs.result: Add test case result for Bug#50423 mysql-test/t/sp-bugs.test: Add test case for Bug#50423 sql/sql_trigger.cc: Backup and reset the query table list. Remove now unnecessary manual reset of the query table list. --- sql/sql_trigger.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index ba0515d38ad..aafb25013f6 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -327,6 +327,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) TABLE *table; bool result= TRUE; String stmt_query; + Query_tables_list backup; bool need_start_waiting= FALSE; DBUG_ENTER("mysql_create_or_drop_trigger"); @@ -393,6 +394,12 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) { bool if_exists= thd->lex->drop_if_exists; + /* + Protect the query table list from the temporary and potentially + destructive changes necessary to open the trigger's table. + */ + thd->lex->reset_n_backup_query_tables_list(&backup); + if (add_table_for_trigger(thd, thd->lex->spname, if_exists, & tables)) goto end; @@ -512,6 +519,10 @@ end: VOID(pthread_mutex_unlock(&LOCK_open)); + /* Restore the query table list. Used only for drop trigger. */ + if (!create) + thd->lex->restore_backup_query_tables_list(&backup); + if (need_start_waiting) start_waiting_global_read_lock(thd); @@ -1625,10 +1636,6 @@ bool add_table_for_trigger(THD *thd, if (load_table_name_for_trigger(thd, trg_name, &trn_path, &tbl_name)) DBUG_RETURN(TRUE); - /* We need to reset statement table list to be PS/SP friendly. */ - lex->query_tables= 0; - lex->query_tables_last= &lex->query_tables; - *table= sp_add_to_query_tables(thd, lex, trg_name->m_db.str, tbl_name.str, TL_IGNORE); -- cgit v1.2.1 From b8eaa81dd95259a0a77ecc6fe9a5d736dc1dfcd6 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Fri, 5 Feb 2010 10:55:20 -0200 Subject: Bug#49025: mysqld-debug: missing DBUG_RETURN or DBUG_VOID_RETURN macro in function "?func" The problem was that the dbug facility was being used after the per-thread dbug state had already been finalized. The was present in a few functions which invoked decrement_handler_count, which in turn invokes my_thread_end on Windows. In my_thread_end, the per-thread dbug state is finalized. Any use after the state is finalized ends up creating a new state. The solution is to process the exit of a function before the decrement_handler_count function is called. sql/mysqld.cc: Process the function exit before decrement_handler_count is called, as it can end the per-thread dbug state on Windows. --- sql/mysqld.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7c45fda1e02..a483b9e2381 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5213,9 +5213,9 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused))) create_new_thread(thd); } - + DBUG_LEAVE; decrement_handler_count(); - DBUG_RETURN(0); + return 0; } @@ -5311,8 +5311,9 @@ pthread_handler_t handle_connections_namedpipes(void *arg) create_new_thread(thd); } CloseHandle(connectOverlapped.hEvent); + DBUG_LEAVE; decrement_handler_count(); - DBUG_RETURN(0); + return 0; } #endif /* __NT__ */ @@ -5548,9 +5549,9 @@ error: if (handle_connect_file_map) CloseHandle(handle_connect_file_map); if (event_connect_answer) CloseHandle(event_connect_answer); if (smem_event_connect_request) CloseHandle(smem_event_connect_request); - + DBUG_LEAVE; decrement_handler_count(); - DBUG_RETURN(0); + return 0; } #endif /* HAVE_SMEM */ #endif /* EMBEDDED_LIBRARY */ -- cgit v1.2.1 From 6d38c898a6c69c2c7f862d40a323f7feec8934d5 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 29 Jan 2010 17:04:37 +0200 Subject: Bug #49324: more valgrind errors in test_if_skip_sort_order Fixed 2 problems : 1. test_if_order_by_key() was continuing on the primary key as if it has a primary key suffix (as the secondary keys do). This leads to crashes in ORDER BY ,. Fixed by not treating the primary key as the secondary one and not depending on it being clustered with a primary key. 2. The cost calculation was trying to read the records per key when operating on ORDER BYs that order on all of the secondary key + some of the primary key. This leads to crashes because of out-of-bounds array access. Fixed by assuming we'll find 1 record per key in such cases. --- sql/sql_select.cc | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bdd139edafc..8744f77d6b1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12813,7 +12813,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, key_part_end=key_part+table->key_info[idx].key_parts; key_part_map const_key_parts=table->const_key_parts[idx]; int reverse=0; - my_bool on_primary_key= FALSE; + my_bool on_pk_suffix= FALSE; DBUG_ENTER("test_if_order_by_key"); for (; order ; order=order->next, const_key_parts>>=1) @@ -12835,11 +12835,12 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, key as a suffix to the secondary keys. If it has continue to check the primary key as a suffix. */ - if (!on_primary_key && + if (!on_pk_suffix && (table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && - table->s->primary_key != MAX_KEY) + table->s->primary_key != MAX_KEY && + table->s->primary_key != idx) { - on_primary_key= TRUE; + on_pk_suffix= TRUE; key_part= table->key_info[table->s->primary_key].key_part; key_part_end=key_part+table->key_info[table->s->primary_key].key_parts; const_key_parts=table->const_key_parts[table->s->primary_key]; @@ -12871,7 +12872,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, reverse=flag; // Remember if reverse key_part++; } - if (on_primary_key) + if (on_pk_suffix) { uint used_key_parts_secondary= table->key_info[idx].key_parts; uint used_key_parts_pk= @@ -13360,8 +13361,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, select_limit= table_records; if (group) { - rec_per_key= used_key_parts ? keyinfo->rec_per_key[used_key_parts-1] - : 1; + /* + Used_key_parts can be larger than keyinfo->key_parts + when using a secondary index clustered with a primary + key (e.g. as in Innodb). + See Bug #28591 for details. + */ + rec_per_key= used_key_parts && + used_key_parts <= keyinfo->key_parts ? + keyinfo->rec_per_key[used_key_parts-1] : 1; set_if_bigger(rec_per_key, 1); /* With a grouping query each group containing on average -- cgit v1.2.1 From 16c8298a85619674f1cce46c081e52f4fbeadb33 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Mon, 1 Feb 2010 16:07:00 +0100 Subject: Bug#42438: Crash ha_partition::change_table_ptr There was two problems: The first was the symptom, caused by bad error handling in ha_partition. It did not handle print_error etc. when having no partitions (when used by dummy handler). The second was the real problem that when dropping tables it reused the table type (storage engine) from when the lock was asked for, not the table type that it had when gaining the exclusive name lock. So that it tried to delete tables from wrong storage engines. Solutions for the first problem was to accept some handler calls to the partitioning handler even if it was not setup with any partitions, and also if possible fallback to use the base handler's default functions. Solution for the second problem was to remove the optimization to reuse the definition from the cache, instead always check the frm-file when holding the LOCK_open mutex (updated with a fix for a debug print crash and better comments as required by reviewer, and removed optimization to avoid reading the frm-file). mysql-test/r/partition_debug_sync.result: Bug#42438: Crash ha_partition::change_table_ptr New result file using DEBUG_SYNC for deterministic results. mysql-test/t/partition_debug_sync.test: Bug#42438: Crash ha_partition::change_table_ptr New test file using DEBUG_SYNC for deterministic results. sql/ha_partition.cc: Bug#42438: Crash ha_partition::change_table_ptr allow some handler calls, used by error handling, even when no partitions are setup. Fallback to default handling if possible. sql/sql_base.cc: Bug#42438: Crash ha_partition::change_table_ptr Added DEBUG_SYNC point for deterministic test cases. sql/sql_table.cc: Bug#42438: Crash ha_partition::change_table_ptr Always use the table type written in the .frm-file (i.e. the current table type) when deleting a table. Moved the check for log-table to not depend of the cache. Added DEBUG_SYNC points for deterministic test cases. --- sql/ha_partition.cc | 33 +++++++++++++++++++++++----- sql/sql_base.cc | 1 + sql/sql_table.cc | 63 +++++++++++++++++++++++++++-------------------------- 3 files changed, 60 insertions(+), 37 deletions(-) (limited to 'sql') diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 451631ff373..099b663f5c2 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1719,13 +1719,23 @@ void ha_partition::update_create_info(HA_CREATE_INFO *create_info) void ha_partition::change_table_ptr(TABLE *table_arg, TABLE_SHARE *share) { - handler **file_array= m_file; + handler **file_array; table= table_arg; table_share= share; - do + /* + m_file can be NULL when using an old cached table in DROP TABLE, when the + table just has REMOVED PARTITIONING, see Bug#42438 + */ + if (m_file) { - (*file_array)->change_table_ptr(table_arg, share); - } while (*(++file_array)); + file_array= m_file; + DBUG_ASSERT(*file_array); + do + { + (*file_array)->change_table_ptr(table_arg, share); + } while (*(++file_array)); + } + if (m_added_file && m_added_file[0]) { /* if in middle of a drop/rename etc */ @@ -5986,7 +5996,13 @@ void ha_partition::print_error(int error, myf errflag) if (error == HA_ERR_NO_PARTITION_FOUND) m_part_info->print_no_partition_found(table); else - m_file[m_last_part]->print_error(error, errflag); + { + /* In case m_file has not been initialized, like in bug#42438 */ + if (m_file) + m_file[m_last_part]->print_error(error, errflag); + else + handler::print_error(error, errflag); + } DBUG_VOID_RETURN; } @@ -5996,7 +6012,12 @@ bool ha_partition::get_error_message(int error, String *buf) DBUG_ENTER("ha_partition::get_error_message"); /* Should probably look for my own errors first */ - DBUG_RETURN(m_file[m_last_part]->get_error_message(error, buf)); + + /* In case m_file has not been initialized, like in bug#42438 */ + if (m_file) + DBUG_RETURN(m_file[m_last_part]->get_error_message(error, buf)); + DBUG_RETURN(handler::get_error_message(error, buf)); + } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index cf8a0b32764..b13a067bfd7 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2165,6 +2165,7 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond) proc_info=thd->proc_info; thd_proc_info(thd, "Waiting for table"); DBUG_ENTER("wait_for_condition"); + DEBUG_SYNC(thd, "waiting_for_table"); if (!thd->killed) (void) pthread_cond_wait(cond, mutex); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 869ae42c98c..5097c0b4945 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -22,6 +22,9 @@ #include "sp_head.h" #include "sql_trigger.h" #include "sql_show.h" +#if defined(ENABLED_DEBUG_SYNC) +#include "debug_sync.h" +#endif #ifdef __WIN__ #include @@ -1870,30 +1873,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, pthread_mutex_lock(&LOCK_open); - /* - If we have the table in the definition cache, we don't have to check the - .frm file to find if the table is a normal table (not view) and what - engine to use. - */ - - for (table= tables; table; table= table->next_local) - { - TABLE_SHARE *share; - table->db_type= NULL; - if ((share= get_cached_table_share(table->db, table->table_name))) - table->db_type= share->db_type(); - - /* Disable drop of enabled log tables */ - if (share && (share->table_category == TABLE_CATEGORY_PERFORMANCE) && - check_if_log_table(table->db_length, table->db, - table->table_name_length, table->table_name, 1)) - { - my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP"); - pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(1); - } - } - if (!drop_temporary && lock_table_names_exclusively(thd, tables)) { pthread_mutex_unlock(&LOCK_open); @@ -1904,7 +1883,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, { char *db=table->db; handlerton *table_type; - enum legacy_db_type frm_db_type; + enum legacy_db_type frm_db_type= DB_TYPE_UNKNOWN; DBUG_PRINT("table", ("table_l: '%s'.'%s' table: 0x%lx s: 0x%lx", table->db, table->table_name, (long) table->table, @@ -1945,6 +1924,15 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, error= 0; } + /* Disable drop of enabled log tables */ + if (check_if_log_table(table->db_length, table->db, + table->table_name_length, table->table_name, 1)) + { + my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP"); + pthread_mutex_unlock(&LOCK_open); + DBUG_RETURN(1); + } + /* If row-based replication is used and the table is not a temporary table, we add the table name to the drop statement @@ -1969,7 +1957,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, built_query.append("`,"); } - table_type= table->db_type; if (!drop_temporary) { TABLE *locked_table; @@ -1996,9 +1983,9 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, table->internal_tmp_table ? FN_IS_TMP : 0); } + DEBUG_SYNC(thd, "rm_table_part2_before_delete_table"); if (drop_temporary || - ((table_type == NULL && - access(path, F_OK) && + ((access(path, F_OK) && ha_create_table_from_engine(thd, db, alias)) || (!drop_view && mysql_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE))) @@ -2014,15 +2001,25 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, else { char *end; - if (table_type == NULL) + /* + Cannot use the db_type from the table, since that might have changed + while waiting for the exclusive name lock. We are under LOCK_open, + so reading from the frm-file is safe. + */ + if (frm_db_type == DB_TYPE_UNKNOWN) { - mysql_frm_type(thd, path, &frm_db_type); - table_type= ha_resolve_by_legacy_type(thd, frm_db_type); + mysql_frm_type(thd, path, &frm_db_type); + DBUG_PRINT("info", ("frm_db_type %d from %s", frm_db_type, path)); } + table_type= ha_resolve_by_legacy_type(thd, frm_db_type); // Remove extension for delete *(end= path + path_length - reg_ext_length)= '\0'; + DBUG_PRINT("info", ("deleting table of type %d", + (table_type ? table_type->db_type : 0))); error= ha_delete_table(thd, table_type, path, db, table->table_name, !dont_log_query); + + /* No error if non existent table and 'IF EXIST' clause or view */ if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && (if_exists || table_type == NULL)) { @@ -2062,6 +2059,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, on the table name. */ pthread_mutex_unlock(&LOCK_open); + DEBUG_SYNC(thd, "rm_table_part2_before_binlog"); thd->thread_specific_used|= tmp_table_deleted; error= 0; if (wrong_tables.length()) @@ -7097,6 +7095,7 @@ view_err: else create_info->data_file_name=create_info->index_file_name=0; + DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock"); /* Create a table with a temporary name. With create_info->frm_only == 1 this creates a .frm file only. @@ -7296,6 +7295,7 @@ view_err: intern_close_table(new_table); my_free(new_table,MYF(0)); } + DEBUG_SYNC(thd, "alter_table_before_rename_result_table"); VOID(pthread_mutex_lock(&LOCK_open)); if (error) { @@ -7438,6 +7438,7 @@ view_err: thd_proc_info(thd, "end"); DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000);); + DEBUG_SYNC(thd, "alter_table_before_main_binlog"); ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE, thd->query(), thd->query_length(), -- cgit v1.2.1 From e925bd737fe60d7c9744daddb440395271d01bd5 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Fri, 5 Feb 2010 17:01:09 +0000 Subject: BUG#48632: Fix for Bug #23300 Has Not Been Backported To 5.x Release Notes ===== This is a backport of BUG#23300 into 5.1 GA. Original cset revid (in betony): luis.soares@sun.com-20090929140901-s4kjtl3iiyy4ls2h Description =========== When using replication, the slave will not log any slow query logs queries replicated from the master, even if the option "--log-slow-slave-statements" is set and these take more than "log_query_time" to execute. In order to log slow queries in replicated thread one needs to set the --log-slow-slave-statements, so that the SQL thread is initialized with the correct switch. Although setting this flag correctly configures the slave thread option to log slow queries, there is an issue with the condition that is used to check whether to log the slow query or not. When replaying binlog events the statement contains the SET TIMESTAMP clause which will force the slow logging condition check to fail. Consequently, the slow query logging will not take place. This patch addresses this issue by removing the second condition from the log_slow_statements as it prevents slow queries to be binlogged and seems to be deprecated. --- sql/log.cc | 1 + sql/sql_parse.cc | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 5544d0010ef..b7313a988c4 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -964,6 +964,7 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length, uint user_host_len= 0; ulonglong query_utime, lock_utime; + DBUG_ASSERT(thd->enable_slow_log); /* Print the message to the buffer if we have slow log enabled */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index df2c1854914..168b16c61bf 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1656,9 +1656,9 @@ void log_slow_statement(THD *thd) /* Do not log administrative statements unless the appropriate option is - set; do not log into slow log if reading from backup. + set. */ - if (thd->enable_slow_log && !thd->user_time) + if (thd->enable_slow_log) { ulonglong end_utime_of_query= thd->current_utime(); thd_proc_info(thd, "logging slow query"); -- cgit v1.2.1 From a0e19f681601979231effab07a2bb6f7e3fbc33c Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Fri, 5 Feb 2010 17:48:01 +0000 Subject: BUG#50620: Adding an index to a table prevents slave from logging into slow log While processing a statement, down the mysql_parse execution stack, the thd->enable_slow_log can be assigned to opt_log_slow_admin_statements, depending whether one is executing administrative statements, such as ALTER TABLE, OPTIMIZE, ANALYZE, etc, or not. This can have an impact on slow logging for statements that are executed after an administrative statement execution is completed. When executing statements directly from the user this is fine because, the thd->enable_slow_log is reset right at the beginning of the dispatch_command function, ie, everytime a new statement is set is set to execute. On the other hand, for slave SQL thread (sql_thd) the story is a bit different. When in SBR the sql_thd applies statements by calling mysql_parse. Right after, it calls log_slow_statement function to log them if they take too long. Calling mysql_parse directly is fine, but also means that dispatch_command function is bypassed. As a consequence, thd->enable_slow_log does not get a chance to be reset before the next statement to be executed by the sql_thd. If the statement just executed by the sql_thd was an administrative statement and logging of admin statements was disabled, this means that sql_thd->enable_slow_log will be set to 0 (disabled) from that moment on. End result: sql_thd stops logging slow statements. We fix this by resetting the value of sql_thd->enable_slow_log to the value of opt_log_slow_slave_statements right after log_slow_stement is called by the sql_thd. --- sql/log_event.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index 2da825e63ce..de395f3d4c7 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3170,6 +3170,18 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, const char* found_semicolon= NULL; mysql_parse(thd, thd->query(), thd->query_length(), &found_semicolon); log_slow_statement(thd); + + /* + Resetting the enable_slow_log thd variable. + + We need to reset it back to the opt_log_slow_slave_statements + value after the statement execution (and slow logging + is done). It might have changed if the statement was an + admin statement (in which case, down in mysql_parse execution + thd->enable_slow_log is set to the value of + opt_log_slow_admin_statements). + */ + thd->enable_slow_log= opt_log_slow_slave_statements; } else { -- cgit v1.2.1 From 3ad5d21ebc981a0b8c59597f0f1a306f3c9d6bf2 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Fri, 5 Feb 2010 17:51:55 +0000 Subject: BUG#50780: 'show binary logs' debug assertion when binary logging is disabled The server would hit an assertion because of a DBUG violation. There was a missing DBUG_RETURN and instead a plain return was used. This patch replaces the return with DBUG_RETURN. --- sql/sql_repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 4b10d284611..ae995ea5ed3 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1606,7 +1606,7 @@ bool show_binlogs(THD* thd) if (!mysql_bin_log.is_open()) { my_message(ER_NO_BINARY_LOGGING, ER(ER_NO_BINARY_LOGGING), MYF(0)); - return 1; + DBUG_RETURN(TRUE); } field_list.push_back(new Item_empty_string("Log_name", 255)); -- cgit v1.2.1 From 994c0f83083ceee30430f28b8f1ced9b71944dbb Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Sat, 6 Feb 2010 23:54:30 +0400 Subject: Bug #45640: optimizer bug produces wrong results Grouping by a subquery in a query with a distinct aggregate function lead to a wrong result (wrong and unordered grouping values). There are two related problems: 1) The query like this: SELECT (SELECT t1.a) aa, COUNT(DISTINCT b) c FROM t1 GROUP BY aa returned wrong result, because the outer reference "t1.a" in the subquery was substituted with the Item_ref item. The Item_ref item obtains data from the result_field object that refreshes once after the end of each group. This data is not applicable to filesort since filesort() doesn't care about groups (and doesn't update result_field objects with copy_fields() and so on). Also that data is not applicable to group separation algorithm: end_send_group() checks every record with test_if_group_changed() that evaluates Item_ref items, but it refreshes those Item_ref-s only after the end of group, that is a vicious circle and the grouped column values in the output are shifted. Fix: if a) we grouping by a subquery and b) that subquery has outer references to FROM list of the grouping query, then we substitute these outer references with Item_direct_ref like references under aggregate functions: Item_direct_ref obtains data directly from the current record. 2) The query with a non-trivial grouping expression like: SELECT (SELECT t1.a) aa, COUNT(DISTINCT b) c FROM t1 GROUP BY aa+0 also returned wrong result, since JOIN::exec() substitutes references to top-level aliases in SELECT list with Item_copy caching items. Item_copy items have same refreshing policy as Item_ref items, so the whole groping expression with Item_copy inside returns wrong result in filesort() and end_send_group(). Fix: include aliased items into GROUP BY item tree instead of Item_ref references to them. mysql-test/r/group_by.result: Test case for bug #45640 mysql-test/t/group_by.test: Test case for bug #45640 sql/item.cc: Bug #45640: optimizer bug produces wrong results Item_field::fix_fields() has been modified to resolve aliases in GROUP BY item trees into aliased items instead of Item_ref items. sql/item.h: Bug #45640: optimizer bug produces wrong results - Item::find_item_processor() has been introduced. - Item_ref::walk() has been modified to apply processors to itself too (not only to referenced item). sql/mysql_priv.h: Bug #45640: optimizer bug produces wrong results fix_inner_refs() has been modified to accept group_list parameter. sql/sql_lex.cc: Bug #45640: optimizer bug produces wrong results Initialization of st_select_lex::group_fix_field has been added. sql/sql_lex.h: Bug #45640: optimizer bug produces wrong results The st_select_lex::group_fix_field field has been introduced to control alias resolution in Itef_fied::fix_fields. sql/sql_select.cc: Bug #45640: optimizer bug produces wrong results - The fix_inner_refs function has been modified to treat subquery outer references like outer fields under aggregate functions, if they are included in GROUP BY item tree. - The find_order_in_list function has been modified to fix Item_field alias fields included in the GROUP BY item trees in a special manner. --- sql/item.cc | 28 ++++++++++++++++++++++------ sql/item.h | 6 +++++- sql/mysql_priv.h | 2 +- sql/sql_lex.cc | 1 + sql/sql_lex.h | 2 ++ sql/sql_select.cc | 46 ++++++++++++++++++++++++++++++++++++++++++---- 6 files changed, 73 insertions(+), 12 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 68c10c32b50..c967a1a0feb 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4300,17 +4300,33 @@ bool Item_field::fix_fields(THD *thd, Item **reference) It's not an Item_field in the select list so we must make a new Item_ref to point to the Item in the select list and replace the Item_field created by the parser with the new Item_ref. + + NOTE: If we are fixing an alias reference inside ORDER/GROUP BY + item tree, then we use new Item_ref as an intermediate value + to resolve referenced item only. + In this case the new Item_ref item is unused. */ Item_ref *rf= new Item_ref(context, db_name,table_name,field_name); if (!rf) return 1; - thd->change_item_tree(reference, rf); + + bool save_group_fix_field= thd->lex->current_select->group_fix_field; /* - Because Item_ref never substitutes itself with other items - in Item_ref::fix_fields(), we can safely use the original - pointer to it even after fix_fields() - */ - return rf->fix_fields(thd, reference) || rf->check_cols(1); + No need for recursive resolving of aliases. + */ + thd->lex->current_select->group_fix_field= 0; + + bool ret= rf->fix_fields(thd, (Item **) &rf) || rf->check_cols(1); + thd->lex->current_select->group_fix_field= save_group_fix_field; + if (ret) + return TRUE; + + if (save_group_fix_field && alias_name_used) + thd->change_item_tree(reference, *rf->ref); + else + thd->change_item_tree(reference, rf); + + return FALSE; } } } diff --git a/sql/item.h b/sql/item.h index 88e90924fcc..d2e8382023b 100644 --- a/sql/item.h +++ b/sql/item.h @@ -901,6 +901,7 @@ public: virtual bool change_context_processor(uchar *context) { return 0; } virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; } virtual bool is_expensive_processor(uchar *arg) { return 0; } + virtual bool find_item_processor(uchar *arg) { return this == (void *) arg; } virtual bool register_field_in_read_map(uchar *arg) { return 0; } /* Check if a partition function is allowed @@ -2275,7 +2276,10 @@ public: return ref ? (*ref)->real_item() : this; } bool walk(Item_processor processor, bool walk_subquery, uchar *arg) - { return (*ref)->walk(processor, walk_subquery, arg); } + { + return (*ref)->walk(processor, walk_subquery, arg) || + (this->*processor)(arg); + } virtual void print(String *str, enum_query_type query_type); bool result_as_longlong() { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 34f29e7c458..1b775e658f1 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1192,7 +1192,7 @@ int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, List &fields, List &all_fields, ORDER *order, bool *hidden_group_fields); bool fix_inner_refs(THD *thd, List &all_fields, SELECT_LEX *select, - Item **ref_pointer_array); + Item **ref_pointer_array, ORDER *group_list= NULL); bool handle_select(THD *thd, LEX *lex, select_result *result, ulong setup_tables_done_option); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 2adbc44eb12..5097ca2ad5b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1592,6 +1592,7 @@ void st_select_lex::init_query() having= prep_having= where= prep_where= 0; olap= UNSPECIFIED_OLAP_TYPE; having_fix_field= 0; + group_fix_field= 0; context.select_lex= this; context.init(); /* diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4e4794ef2cf..459878c03fc 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -647,6 +647,8 @@ public: bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */ /* TRUE when having fix field called in processing of this SELECT */ bool having_fix_field; + /* TRUE when GROUP BY fix field called in processing of this SELECT */ + bool group_fix_field; /* List of references to fields referenced from inner selects */ List inner_refs_list; /* Number of Item_sum-derived objects in this SELECT */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8744f77d6b1..ec880f3703e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -287,6 +287,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, all_fields List of all fields used in select select Current select ref_pointer_array Array of references to Items used in current select + group_list GROUP BY list (is NULL by default) DESCRIPTION The function serves 3 purposes - adds fields referenced from inner @@ -305,6 +306,8 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, function is aggregated in the select where the outer field was resolved or in some more inner select then the Item_direct_ref class should be used. + Also it should be used if we are grouping by a subquery containing + the outer field. The resolution is done here and not at the fix_fields() stage as it can be done only after sum functions are fixed and pulled up to selects where they are have to be aggregated. @@ -321,7 +324,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, bool fix_inner_refs(THD *thd, List &all_fields, SELECT_LEX *select, - Item **ref_pointer_array) + Item **ref_pointer_array, ORDER *group_list) { Item_outer_ref *ref; bool res= FALSE; @@ -371,6 +374,22 @@ fix_inner_refs(THD *thd, List &all_fields, SELECT_LEX *select, } } } + else + { + /* + Check if GROUP BY item trees contain the outer ref: + in this case we have to use Item_direct_ref instead of Item_ref. + */ + for (ORDER *group= group_list; group; group= group->next) + { + if ((*group->item)->walk(&Item::find_item_processor, TRUE, + (uchar *) ref)) + { + direct_ref= TRUE; + break; + } + } + } new_ref= direct_ref ? new Item_direct_ref(ref->context, item_ref, ref->table_name, ref->field_name, ref->alias_name_used) : @@ -577,7 +596,8 @@ JOIN::prepare(Item ***rref_pointer_array, } if (select_lex->inner_refs_list.elements && - fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array)) + fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array, + group_list)) DBUG_RETURN(-1); if (group_list) @@ -14547,11 +14567,29 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, We check order_item->fixed because Item_func_group_concat can put arguments for which fix_fields already was called. + + group_fix_field= TRUE is to resolve aliases from the SELECT list + without creating of Item_ref-s: JOIN::exec() wraps aliased items + in SELECT list with Item_copy items. To re-evaluate such a tree + that includes Item_copy items we have to refresh Item_copy caches, + but: + - filesort() never refresh Item_copy items, + - end_send_group() checks every record for group boundary by the + test_if_group_changed function that obtain data from these + Item_copy items, but the copy_fields function that + refreshes Item copy items is called after group boundaries only - + that is a vicious circle. + So we prevent inclusion of Item_copy items. */ - if (!order_item->fixed && + bool save_group_fix_field= thd->lex->current_select->group_fix_field; + if (is_group_field) + thd->lex->current_select->group_fix_field= TRUE; + bool ret= (!order_item->fixed && (order_item->fix_fields(thd, order->item) || (order_item= *order->item)->check_cols(1) || - thd->is_fatal_error)) + thd->is_fatal_error)); + thd->lex->current_select->group_fix_field= save_group_fix_field; + if (ret) return TRUE; /* Wrong field. */ uint el= all_fields.elements; -- cgit v1.2.1 From 0897669cba1b314c36f41a8a31ee73b6d0d11115 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Tue, 9 Feb 2010 12:53:13 +0400 Subject: BUG#49902 - SELECT returns incorrect results Queries optimized with GROUP_MIN_MAX didn't cleanup KEYREAD optimization properly. As a result subsequent queries may return incomplete rows (fields are initialized to default values). mysql-test/r/group_min_max.result: A test case for BUG#49902. mysql-test/t/group_min_max.test: A test case for BUG#49902. sql/opt_range.cc: Refactor of KEYREAD optimization switch so that KEYREAD handler state is in sync with st_table::key_read flag. All SQL code is supposed to switch KEYREAD optimization via st_table::set_keyread(). sql/opt_sum.cc: Refactor of KEYREAD optimization switch so that KEYREAD handler state is in sync with st_table::key_read flag. All SQL code is supposed to switch KEYREAD optimization via st_table::set_keyread(). sql/sql_select.cc: Refactor of KEYREAD optimization switch so that KEYREAD handler state is in sync with st_table::key_read flag. All SQL code is supposed to switch KEYREAD optimization via st_table::set_keyread(). sql/sql_update.cc: Refactor of KEYREAD optimization switch so that KEYREAD handler state is in sync with st_table::key_read flag. All SQL code is supposed to switch KEYREAD optimization via st_table::set_keyread(). sql/table.cc: Refactor of KEYREAD optimization switch so that KEYREAD handler state is in sync with st_table::key_read flag. All SQL code is supposed to switch KEYREAD optimization via st_table::set_keyread(). sql/table.h: Refactor of KEYREAD optimization switch so that KEYREAD handler state is in sync with st_table::key_read flag. All SQL code is supposed to switch KEYREAD optimization via st_table::set_keyread(). --- sql/opt_range.cc | 15 ++++--------- sql/opt_sum.cc | 17 +++----------- sql/sql_select.cc | 66 +++++++++++++------------------------------------------ sql/sql_update.cc | 9 +------- sql/table.cc | 5 ++--- sql/table.h | 14 ++++++++++++ 6 files changed, 39 insertions(+), 87 deletions(-) (limited to 'sql') diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 94204962345..34757a44c2f 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1171,11 +1171,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() if (file) { range_end(); - if (head->key_read) - { - head->key_read= 0; - file->extra(HA_EXTRA_NO_KEYREAD); - } + head->set_keyread(FALSE); if (free_file) { DBUG_PRINT("info", ("Freeing separate handler 0x%lx (free: %d)", (long) file, @@ -1377,10 +1373,7 @@ end: head->file= file; /* We don't have to set 'head->keyread' here as the 'file' is unique */ if (!head->no_keyread) - { - head->key_read= 1; head->mark_columns_used_by_index(index); - } head->prepare_for_position(); head->file= org_file; bitmap_copy(&column_bitmap, head->read_set); @@ -8165,7 +8158,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::read_keys_and_merge"); /* We're going to just read rowids. */ - file->extra(HA_EXTRA_KEYREAD); + head->set_keyread(TRUE); head->prepare_for_position(); cur_quick_it.rewind(); @@ -8241,7 +8234,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() delete unique; doing_pk_scan= FALSE; /* index_merge currently doesn't support "using index" at all */ - file->extra(HA_EXTRA_NO_KEYREAD); + head->set_keyread(FALSE); init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1 , 1, TRUE); DBUG_RETURN(result); } @@ -10628,7 +10621,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(void) int result; DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::reset"); - file->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */ + head->set_keyread(TRUE); /* We need only the key attributes */ if ((result= file->ha_index_init(index,1))) DBUG_RETURN(result); if (quick_prefix_select && quick_prefix_select->reset()) diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index e009cf1ca9f..70d6d0a5b17 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -326,11 +326,7 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) if (!error && reckey_in_range(0, &ref, item_field->field, conds, range_fl, prefix_len)) error= HA_ERR_KEY_NOT_FOUND; - if (table->key_read) - { - table->key_read= 0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + table->set_keyread(FALSE); table->file->ha_index_end(); if (error) { @@ -413,11 +409,7 @@ int opt_sum_query(TABLE_LIST *tables, List &all_fields,COND *conds) if (!error && reckey_in_range(1, &ref, item_field->field, conds, range_fl, prefix_len)) error= HA_ERR_KEY_NOT_FOUND; - if (table->key_read) - { - table->key_read=0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + table->set_keyread(FALSE); table->file->ha_index_end(); if (error) { @@ -876,10 +868,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, converted (for example to upper case) */ if (field->part_of_key.is_set(idx)) - { - table->key_read= 1; - table->file->extra(HA_EXTRA_KEYREAD); - } + table->set_keyread(TRUE); return 1; } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d5ce32902c4..ab8b65b5cc7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6594,10 +6594,7 @@ make_join_readinfo(JOIN *join, ulonglong options) case JT_CONST: // Only happens with left join if (table->covering_keys.is_set(tab->ref.key) && !table->no_keyread) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } + table->set_keyread(TRUE); break; case JT_ALL: /* @@ -6658,10 +6655,7 @@ make_join_readinfo(JOIN *join, ulonglong options) if (tab->select && tab->select->quick && tab->select->quick->index != MAX_KEY && //not index_merge table->covering_keys.is_set(tab->select->quick->index)) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } + table->set_keyread(TRUE); else if (!table->covering_keys.is_clear_all() && !(tab->select && tab->select->quick)) { // Only read index tree @@ -6745,11 +6739,7 @@ void JOIN_TAB::cleanup() limit= 0; if (table) { - if (table->key_read) - { - table->key_read= 0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + table->set_keyread(FALSE); table->file->ha_index_or_rnd_end(); /* We need to reset this for next select @@ -11595,16 +11585,11 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) !table->no_keyread && (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY) { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); + table->set_keyread(TRUE); tab->index= tab->ref.key; } error=join_read_const(tab); - if (table->key_read) - { - table->key_read=0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + table->set_keyread(FALSE); if (error) { tab->info="unique row not found"; @@ -11959,12 +11944,8 @@ join_read_first(JOIN_TAB *tab) { int error; TABLE *table=tab->table; - if (!table->key_read && table->covering_keys.is_set(tab->index) && - !table->no_keyread) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } + if (table->covering_keys.is_set(tab->index) && !table->no_keyread) + table->set_keyread(TRUE); tab->table->status=0; tab->read_record.read_record=join_read_next; tab->read_record.table=table; @@ -11998,12 +11979,8 @@ join_read_last(JOIN_TAB *tab) { TABLE *table=tab->table; int error; - if (!table->key_read && table->covering_keys.is_set(tab->index) && - !table->no_keyread) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } + if (table->covering_keys.is_set(tab->index) && !table->no_keyread) + table->set_keyread(TRUE); tab->table->status=0; tab->read_record.read_record=join_read_prev; tab->read_record.table=table; @@ -13413,11 +13390,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, If ref_key used index tree reading only ('Using index' in EXPLAIN), and best_key doesn't, then revert the decision. */ - if (!table->covering_keys.is_set(best_key) && table->key_read) - { - table->key_read= 0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + if (!table->covering_keys.is_set(best_key)) + table->set_keyread(FALSE); if (!quick_created) { tab->index= best_key; @@ -13430,10 +13404,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, select->quick= 0; } if (table->covering_keys.is_set(best_key)) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } + table->set_keyread(TRUE); table->file->ha_index_or_rnd_end(); if (join->select_options & SELECT_DESCRIBE) { @@ -13607,11 +13578,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, We can only use 'Only index' if quick key is same as ref_key and in index_merge 'Only index' cannot be used */ - if (table->key_read && ((uint) tab->ref.key != select->quick->index)) - { - table->key_read=0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + if (((uint) tab->ref.key != select->quick->index)) + table->set_keyread(FALSE); } else { @@ -13667,11 +13635,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, tab->type=JT_ALL; // Read with normal read_record tab->read_first_record= join_init_read_record; tab->join->examined_rows+=examined_rows; - if (table->key_read) // Restore if we used indexes - { - table->key_read=0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + table->set_keyread(FALSE); // Restore if we used indexes DBUG_RETURN(table->sort.found_records == HA_POS_ERROR); err: DBUG_RETURN(-1); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 433e2619aca..32add8679ef 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -397,10 +397,7 @@ int mysql_update(THD *thd, matching rows before updating the table! */ if (used_index < MAX_KEY && old_covering_keys.is_set(used_index)) - { - table->key_read=1; table->mark_columns_used_by_index(used_index); - } else { table->use_all_columns(); @@ -844,11 +841,7 @@ int mysql_update(THD *thd, err: delete select; free_underlaid_joins(thd, select_lex); - if (table->key_read) - { - table->key_read=0; - table->file->extra(HA_EXTRA_NO_KEYREAD); - } + table->set_keyread(FALSE); thd->abort_on_warning= 0; DBUG_RETURN(1); } diff --git a/sql/table.cc b/sql/table.cc index c06ecf99926..9561e5fcc4b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4374,7 +4374,7 @@ void st_table::mark_columns_used_by_index(uint index) MY_BITMAP *bitmap= &tmp_set; DBUG_ENTER("st_table::mark_columns_used_by_index"); - (void) file->extra(HA_EXTRA_KEYREAD); + set_keyread(TRUE); bitmap_clear_all(bitmap); mark_columns_used_by_index_no_reset(index, bitmap); column_bitmaps_set(bitmap, bitmap); @@ -4397,8 +4397,7 @@ void st_table::restore_column_maps_after_mark_index() { DBUG_ENTER("st_table::restore_column_maps_after_mark_index"); - key_read= 0; - (void) file->extra(HA_EXTRA_NO_KEYREAD); + set_keyread(FALSE); default_column_bitmaps(); file->column_bitmaps_signal(); DBUG_VOID_RETURN; diff --git a/sql/table.h b/sql/table.h index eae261cc97d..e797ef2b2de 100644 --- a/sql/table.h +++ b/sql/table.h @@ -902,6 +902,20 @@ struct st_table { inline bool needs_reopen_or_name_lock() { return s->version != refresh_version; } bool is_children_attached(void); + inline void set_keyread(bool flag) + { + DBUG_ASSERT(file); + if (flag && !key_read) + { + key_read= 1; + file->extra(HA_EXTRA_KEYREAD); + } + else if (!flag && key_read) + { + key_read= 0; + file->extra(HA_EXTRA_NO_KEYREAD); + } + } }; enum enum_schema_table_state -- cgit v1.2.1 From e0fb0d9d018e0bc1a2da9f62a929cf669efd8343 Mon Sep 17 00:00:00 2001 From: Magne Mahre Date: Tue, 9 Feb 2010 11:30:50 +0100 Subject: Bug#47974 'TYPE=storage_engine' is deprecated and will be removed in MySQL 6.0 CREATE TABLE... TYPE= returns the warning "The syntax 'TYPE=storage_engine' is deprecated and will be removed in MySQL 6.0. Please use 'ENGINE=storage_engine' instead" This syntax is deprecated already from version 5.4.4, so the message has been changed. In addition, the deprecation macro was changed to reflect the ServerPT decision not to include version number in the warning message. A number of test result files have been changed as a consequence of the change in the deprecation macro. --- sql/mysql_priv.h | 12 +++++++----- sql/share/errmsg.txt | 2 +- sql/sql_yacc.yy | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 1b775e658f1..90b02f5337a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -118,13 +118,15 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); #define WARN_DEPRECATED(Thd,Ver,Old,New) \ do { \ DBUG_ASSERT(strncmp(Ver, MYSQL_SERVER_VERSION, sizeof(Ver)-1) > 0); \ - if (((uchar*)Thd) != NULL) \ + if (((uchar*)Thd) != NULL) \ push_warning_printf(((THD *)Thd), MYSQL_ERROR::WARN_LEVEL_WARN, \ - ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX_WITH_VER), \ - (Old), (Ver), (New)); \ + ER_WARN_DEPRECATED_SYNTAX, \ + ER(ER_WARN_DEPRECATED_SYNTAX), \ + (Old), (New)); \ else \ - sql_print_warning("The syntax '%s' is deprecated and will be removed " \ - "in a future release. Please use %s instead.", (Old), (New)); \ + sql_print_warning("'%s' is deprecated and will be removed " \ + "in a future release. Please use '%s' instead.", \ + (Old), (New)); \ } while(0) extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 06ce848399b..bbae17c4327 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5027,7 +5027,7 @@ ER_UNKNOWN_STORAGE_ENGINE 42000 # When using this error code, use ER(ER_WARN_DEPRECATED_SYNTAX_WITH_VER) # for the message string. See, for example, code in mysql_priv.h. ER_WARN_DEPRECATED_SYNTAX - eng "'%s' is deprecated; use '%s' instead" + eng "'%s' is deprecated and will be removed in a future release. Please use %s instead" ger "'%s' ist veraltet. Bitte benutzen Sie '%s'" por "'%s' é desatualizado. Use '%s' em seu lugar" spa "'%s' está desaprobado, use '%s' en su lugar" diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8dc08f8425f..37150bf835d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4596,7 +4596,7 @@ create_table_option: | TYPE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; - WARN_DEPRECATED(yythd, "6.0", "TYPE=storage_engine", + WARN_DEPRECATED(yythd, "5.4.4", "TYPE=storage_engine", "'ENGINE=storage_engine'"); Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE; } -- cgit v1.2.1 From f2aee2371ef3f9140fb4f812ca7dcdcf2f6720bb Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 10 Feb 2010 18:56:47 +0400 Subject: Bug#45195 valgrind warnings about uninitialized values in store_record_in_cache() The problem becomes apparent only if HAVE_purify is undefined. It related to the part of code placed in open_table_from_share() fuction where we initialize record buffer only if HAVE_purify is enabled. So in case of HAVE_purify=OFF record buffer is not initialized on open table stage. Next we read key, find NULL value and update appropriate null bit but do not update record buffer. After that the record is stored in the join cache(store_record_in_cache). For CHAR fields we strip trailing spaces and in our case this procedure uses uninitialized record buffer. The fix is to skip stripping space procedure in case of null values for CHAR fields(partially based on 6.0 JOIN_CACHE implementation). mysql-test/r/join.result: test case mysql-test/t/join.test: test case sql/field.cc: code updated according to new CACHE_FIELD struct sql/sql_select.cc: code updated according to new CACHE_FIELD struct sql/sql_select.h: CACHE_FIELD struct: added new fields: Field *field, uint type; removed fields: Field_blob *blob_field, bool strip; --- sql/field.cc | 11 +++++------ sql/sql_select.cc | 51 +++++++++++++++++++++++++++++---------------------- sql/sql_select.h | 8 ++++++-- 3 files changed, 40 insertions(+), 30 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index d8db3fdbae4..15ee9c4a86c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1705,11 +1705,10 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) uint store_length; copy->str=ptr; copy->length=pack_length(); - copy->blob_field=0; + copy->field= this; if (flags & BLOB_FLAG) { - copy->blob_field=(Field_blob*) this; - copy->strip=0; + copy->type= CACHE_BLOB; copy->length-= table->s->blob_ptr_size; return copy->length; } @@ -1717,15 +1716,15 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) (type() == MYSQL_TYPE_STRING && copy->length >= 4 && copy->length < 256)) { - copy->strip=1; /* Remove end space */ + copy->type= CACHE_STRIPPED; store_length= 2; } else { - copy->strip=0; + copy->type= 0; store_length= 0; } - return copy->length+ store_length; + return copy->length + store_length; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b1efaf67b9b..a3ce50fe4ee 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14149,7 +14149,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count) { used_fields--; length+=field->fill_cache_field(copy); - if (copy->blob_field) + if (copy->type == CACHE_BLOB) (*blob_ptr++)=copy; if (field->real_maybe_null()) null_fields++; @@ -14164,8 +14164,8 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count) { /* must copy null bits */ copy->str= tables[i].table->null_flags; copy->length= tables[i].table->s->null_bytes; - copy->strip=0; - copy->blob_field=0; + copy->type=0; + copy->field=0; length+=copy->length; copy++; cache->fields++; @@ -14175,8 +14175,8 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count) { copy->str= (uchar*) &tables[i].table->null_row; copy->length=sizeof(tables[i].table->null_row); - copy->strip=0; - copy->blob_field=0; + copy->type=0; + copy->field=0; length+=copy->length; copy++; cache->fields++; @@ -14201,9 +14201,10 @@ used_blob_length(CACHE_FIELD **ptr) uint length,blob_length; for (length=0 ; *ptr ; ptr++) { - (*ptr)->blob_length=blob_length=(*ptr)->blob_field->get_length(); + Field_blob *field_blob= (Field_blob *) (*ptr)->field; + (*ptr)->blob_length=blob_length= field_blob->get_length(); length+=blob_length; - (*ptr)->blob_field->get_ptr(&(*ptr)->str); + field_blob->get_ptr(&(*ptr)->str); } return length; } @@ -14232,30 +14233,35 @@ store_record_in_cache(JOIN_CACHE *cache) cache->records++; for (copy=cache->field ; copy < end_field; copy++) { - if (copy->blob_field) + if (copy->type == CACHE_BLOB) { + Field_blob *blob_field= (Field_blob *) copy->field; if (last_record) { - copy->blob_field->get_image(pos, copy->length+sizeof(char*), - copy->blob_field->charset()); + blob_field->get_image(pos, copy->length+sizeof(char*), + blob_field->charset()); pos+=copy->length+sizeof(char*); } else { - copy->blob_field->get_image(pos, copy->length, // blob length - copy->blob_field->charset()); + blob_field->get_image(pos, copy->length, // blob length + blob_field->charset()); memcpy(pos+copy->length,copy->str,copy->blob_length); // Blob data pos+=copy->length+copy->blob_length; } } else { - if (copy->strip) + if (copy->type == CACHE_STRIPPED) { uchar *str,*end; - for (str=copy->str,end= str+copy->length; - end > str && end[-1] == ' ' ; - end--) ; + Field *field= copy->field; + if (field && field->maybe_null() && field->is_null()) + end= str= copy->str; + else + for (str=copy->str,end= str+copy->length; + end > str && end[-1] == ' ' ; + end--) ; length=(uint) (end-str); memcpy(pos+2, str, length); int2store(pos, length); @@ -14304,23 +14310,24 @@ read_cached_record(JOIN_TAB *tab) copy < end_field; copy++) { - if (copy->blob_field) + if (copy->type == CACHE_BLOB) { + Field_blob *blob_field= (Field_blob *) copy->field; if (last_record) { - copy->blob_field->set_image(pos, copy->length+sizeof(char*), - copy->blob_field->charset()); + blob_field->set_image(pos, copy->length+sizeof(char*), + blob_field->charset()); pos+=copy->length+sizeof(char*); } else { - copy->blob_field->set_ptr(pos, pos+copy->length); - pos+=copy->length+copy->blob_field->get_length(); + blob_field->set_ptr(pos, pos+copy->length); + pos+=copy->length + blob_field->get_length(); } } else { - if (copy->strip) + if (copy->type == CACHE_STRIPPED) { length= uint2korr(pos); memcpy(copy->str, pos+2, length); diff --git a/sql/sql_select.h b/sql/sql_select.h index bfff0a0ffa2..ef43f9b049c 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -95,6 +95,10 @@ typedef struct st_table_ref } TABLE_REF; + +#define CACHE_BLOB 1 /* blob field */ +#define CACHE_STRIPPED 2 /* field stripped of trailing spaces */ + /** CACHE_FIELD and JOIN_CACHE is used on full join to cache records in outer table @@ -103,8 +107,8 @@ typedef struct st_table_ref typedef struct st_cache_field { uchar *str; uint length, blob_length; - Field_blob *blob_field; - bool strip; + Field *field; + uint type; /**< category of the of the copied field (CACHE_BLOB et al.) */ } CACHE_FIELD; -- cgit v1.2.1 From 792fc9f7844575675206f873a0fa1d6e7fb8ad4f Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 12 Feb 2010 18:28:35 +0200 Subject: Bug #35250: readline check breaks when doing vpath build Fixed several (obvious) places that don't work with vpath build. --- sql/share/Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am index 68b393e619f..357f9ac0876 100644 --- a/sql/share/Makefile.am +++ b/sql/share/Makefile.am @@ -22,7 +22,7 @@ dist-hook: test -d $(distdir)/$$dir || mkdir $(distdir)/$$dir; \ $(INSTALL_DATA) $(srcdir)/$$dir/*.* $(distdir)/$$dir; \ done; \ - sleep 1 ; touch $(srcdir)/*/errmsg.sys + sleep 1 ; touch $(builddir)/*/errmsg.sys $(INSTALL_DATA) $(srcdir)/charsets/README $(distdir)/charsets $(INSTALL_DATA) $(srcdir)/charsets/Index.xml $(distdir)/charsets @@ -39,11 +39,11 @@ install-data-local: for lang in @AVAILABLE_LANGUAGES@; \ do \ $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/$$lang; \ - $(INSTALL_DATA) $(srcdir)/$$lang/errmsg.sys \ + $(INSTALL_DATA) $(builddir)/$$lang/errmsg.sys \ $(DESTDIR)$(pkgdatadir)/$$lang/errmsg.sys; \ done $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/charsets - $(INSTALL_DATA) $(srcdir)/errmsg.txt \ + $(INSTALL_DATA) $(builddir)/errmsg.txt \ $(DESTDIR)$(pkgdatadir)/errmsg.txt; \ $(INSTALL_DATA) $(srcdir)/charsets/README $(DESTDIR)$(pkgdatadir)/charsets/README $(INSTALL_DATA) $(srcdir)/charsets/*.xml $(DESTDIR)$(pkgdatadir)/charsets @@ -53,7 +53,7 @@ uninstall-local: @RM@ -f -r $(DESTDIR)$(pkgdatadir) distclean-local: - @RM@ -f */errmsg.sys + @RM@ -f $(builddir)/*/errmsg.sys # Do nothing link_sources: -- cgit v1.2.1 From 07c30f911e86b34f004f15b26771a4b20a513b15 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Sat, 13 Feb 2010 08:35:14 -0200 Subject: Bug#50624: crash in check_table_access during call procedure This bug is just one facet of stored routines not being able to detect changes in meta-data (WL#4179). This particular problem can be triggered within a single session due to the improper management of the pre-locking list if the view is expanded after the pre-locking list is calculated. Since the overall solution for the meta-data detection issue is planned for a later release, for now a workaround is used to fix this particular aspect that only involves a single session. The workaround is to flush the thread-local stored routine cache every time a view is created or modified, causing locally cached routines to be re-evaluated upon invocation. mysql-test/r/sp-bugs.result: Add test case result for Bug#50624. mysql-test/t/sp-bugs.test: Add test case for Bug#50624. sql/sp_cache.cc: Update function description. sql/sql_view.cc: Invalidate the SP cache if a view is being created or modified. --- sql/sp_cache.cc | 5 +++-- sql/sql_view.cc | 13 +++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index b8209a373a2..12d21aee22c 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -175,8 +175,9 @@ sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name) sp_cache_invalidate() NOTE - This is called when a VIEW definition is modifed. We can't destroy sp_head - objects here as one may modify VIEW definitions from prelocking-free SPs. + This is called when a VIEW definition is created or modified (and in some + other contexts). We can't destroy sp_head objects here as one may modify + VIEW definitions from prelocking-free SPs. */ void sp_cache_invalidate() diff --git a/sql/sql_view.cc b/sql/sql_view.cc index c6d412112c2..c66990c54c6 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -400,17 +400,14 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, DBUG_ASSERT(!lex->proc_list.first && !lex->result && !lex->param_list.elements); - if (mode != VIEW_CREATE_NEW) + if (mode == VIEW_ALTER && fill_defined_view_parts(thd, view)) { - if (mode == VIEW_ALTER && - fill_defined_view_parts(thd, view)) - { - res= TRUE; - goto err; - } - sp_cache_invalidate(); + res= TRUE; + goto err; } + sp_cache_invalidate(); + if (!lex->definer) { /* -- cgit v1.2.1 From 32058ba9c6365f1190e36c290ced9779f79cbdfe Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 15 Feb 2010 10:54:27 +0200 Subject: Addendum 2 for bug #46175: NULL read_view and consistent read assertion Fixed a compilation warning. --- sql/sql_select.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.h b/sql/sql_select.h index 8d3520bf9c8..b39827ef61b 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -769,7 +769,7 @@ protected: if ((res= item->save_in_field(to_field, 1))) { if (!err) - err= res; + err= res < 0 ? 1 : res; /* 1=STORE_KEY_FATAL */ } /* Item::save_in_field() may call Item::val_xxx(). And if this is a subquery @@ -779,7 +779,7 @@ protected: err= 1; /* STORE_KEY_FATAL */ } null_key= to_field->is_null() || item->null_value; - return ((err < 0 || err > 2) ? STORE_KEY_FATAL : (store_key_result) err); + return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err); } }; -- cgit v1.2.1 From 82e2d858a441295e3c2d2714df43f8118ff7048f Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Tue, 16 Feb 2010 13:13:49 +0400 Subject: Bug#50591 bit(31) causes Duplicate entry '1-NULL' for key 'group_key' The problem is that during temporary table creation uneven bits are not taken into account for hidden fields. It leads to incorrect calculation&allocation of null bytes size for table record. And if grouped value is null we set wrong bit for this value(see end_update()). Fixed by adding separate calculation of uneven bit for hidden fields. mysql-test/r/type_bit.result: test case mysql-test/t/type_bit.test: test case sql/sql_select.cc: added separate calculation of uneven bit for hidden fields --- sql/sql_select.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a3ce50fe4ee..52f9aae7a0c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9822,7 +9822,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, KEY_PART_INFO *key_part_info; Item **copy_func; MI_COLUMNDEF *recinfo; - uint total_uneven_bit_length= 0; + /* + total_uneven_bit_length is uneven bit length for visible fields + hidden_uneven_bit_length is uneven bit length for hidden fields + */ + uint total_uneven_bit_length= 0, hidden_uneven_bit_length= 0; bool force_copy_fields= param->force_copy_fields; /* Treat sum functions as normal ones when loose index scan is used. */ save_sum_fields|= param->precomputed_group_by; @@ -10099,6 +10103,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, */ param->hidden_field_count= fieldnr; null_count= 0; + /* + On last hidden field we store uneven bit length in + hidden_uneven_bit_length and proceed calculation of + uneven bits for visible fields into + total_uneven_bit_length variable. + */ + hidden_uneven_bit_length= total_uneven_bit_length; + total_uneven_bit_length= 0; } } DBUG_ASSERT(fieldnr == (uint) (reg_field - table->field)); @@ -10144,7 +10156,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, else null_count++; } - hidden_null_pack_length=(hidden_null_count+7)/8; + hidden_null_pack_length= (hidden_null_count + 7 + + hidden_uneven_bit_length) / 8; null_pack_length= (hidden_null_pack_length + (null_count + total_uneven_bit_length + 7) / 8); reclength+=null_pack_length; -- cgit v1.2.1 From 6cb7abe667533084e09f3df6951591332138ae0e Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 16 Feb 2010 11:42:22 +0100 Subject: post push fix for bug#42438, did not compile on non debug, due to ifdef of include file sql/sql_table.cc: removed if defined since DEBUG_SYNC macro is defined in that include file. --- sql/sql_table.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b201fbc3d3e..871b2f2d552 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -22,9 +22,7 @@ #include "sp_head.h" #include "sql_trigger.h" #include "sql_show.h" -#if defined(ENABLED_DEBUG_SYNC) #include "debug_sync.h" -#endif #ifdef __WIN__ #include -- cgit v1.2.1 From 4b260b668d66cfd6f7e8c2612461c66d2914219d Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 17 Feb 2010 16:13:42 +0400 Subject: Bug#33717 INSERT...(default) fails for enum. Crashes CSV tables, loads spaces for MyISAM Table corruption happens during table reading in ha_tina::find_current_row() func. Field::store() method returns error(true) if stored value is 0. The fix: added special case for enum type which correctly processes 0 value. Additional fix: INSERT...(default) and INSERT...() have the same behaviour now for enum type. mysql-test/r/csv.result: test result mysql-test/r/default.result: result fix mysql-test/t/csv.test: test case sql/item.cc: Changes: do not print warning for 'enum' type if there is no default value. set default value. storage/csv/ha_tina.cc: Table corruption happens during table reading in ha_tina::find_current_row() func. Field::store() method returns error(true) if stored value is 0. The fix: added special case for enum type which correctly processes 0 value. --- sql/item.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index df266434f72..f8cca3a0667 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6488,7 +6488,8 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) { if (!arg) { - if (field_arg->flags & NO_DEFAULT_VALUE_FLAG) + if (field_arg->flags & NO_DEFAULT_VALUE_FLAG && + field_arg->real_type() != MYSQL_TYPE_ENUM) { if (field_arg->reset()) { -- cgit v1.2.1 From f0b38904aaca492acb408aaf571758d9a8f9b83d Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Wed, 17 Feb 2010 18:07:28 +0000 Subject: BUG#48993: valgrind errors in mysqlbinlog I found three issues during the analysis: 1. Memory leak caused by temp_buf not being freed; 2. Memory leak caused when handling argv; 3. Conditional jump that depended on unitialized values. Issue #1 -------- DESCRIPTION: when mysqlbinlog is reading from a remote location the event temp_buf references the incoming stream (in NET object), which is not freed by mysqlbinlog explicitly. On the other hand, when it is reading local binary log, it points to a temporary buffer that needs to be explicitly freed. For both cases, the temp_buf was not freed by mysqlbinlog, instead was set to 0. This clearly disregards the free required in the second case, thence creating a memory leak. FIX: we make temp_buf to be conditionally freed depending on the value of remote_opt. Found out that similar fix is already in most recent codebases. Issue #2 -------- DESCRIPTION: load_defaults is called by parse_args, and it reads default options from configuration files and put them BEFORE the arguments that are already in argc and argv. This is done resorting to MEM_ROOT. However, parse_args calls handle_options immediately after which changes argv. Later when freeing the defaults, pointers to MEM_ROOT won't match, causing the memory not to be freed: void free_defaults(char **argv) { MEM_ROOT ptr memcpy_fixed((char*) &ptr,(char *) argv - sizeof(ptr), sizeof(ptr)); free_root(&ptr,MYF(0)); } FIX: we remove load_defaults from parse_args and call it before. Then we save argv with defaults in defaults_argv BEFORE calling parse_args (which inside can then call handle_options at will). Actually, found out that this is in fact kind of a backport for BUG#38468 into 5.1, so I merged in the test case as well and added error check for load_defaults call. Fix based on: revid:zhenxing.he@sun.com-20091002081840-uv26f0flw4uvo33y Issue #3 -------- DESCRIPTION: the structure st_print_event_info constructor would not initialize the sql_mode member, although it did for sql_mode_inited (set to false). This would later raise the warning in valgrind when printing the sql_mode in the event header, as this print out is protected by a check against sql_mode_inited and sql_mode variables. Given that sql_mode was not initialized valgrind would output the warning. FIX: we add initialization of sql_mode to the st_print_event_info constructor. client/mysqlbinlog.cc: - Conditionally free ev->temp_buf. - save defaults_argv before handle_options is called. mysql-test/t/mysqlbinlog.test: Added test case from BUG#38468. sql/log_event.cc: Added initialization of sql_mode for st_print_event_info. --- sql/log_event.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index de395f3d4c7..2398f33dc23 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -9478,7 +9478,7 @@ Incident_log_event::write_data_body(IO_CACHE *file) they will always be printed for the first event. */ st_print_event_info::st_print_event_info() - :flags2_inited(0), sql_mode_inited(0), + :flags2_inited(0), sql_mode_inited(0), sql_mode(0), auto_increment_increment(0),auto_increment_offset(0), charset_inited(0), lc_time_names_number(~0), charset_database_number(ILLEGAL_CHARSET_INFO_NUMBER), -- cgit v1.2.1 From e0fbc5d248e4d35920553417f13701484b20f622 Mon Sep 17 00:00:00 2001 From: "Tatiana A. Nurnberg" Date: Thu, 18 Feb 2010 17:02:17 +0000 Subject: Bug#48525: trigger changes "Column 'id' cannot be null" behaviour CHECK_FIELD_IGNORE was treated as CHECK_FIELD_ERROR_FOR_NULL; UPDATE...SET...NULL on NOT NULL fields behaved differently after a trigger. Now distinguishes between IGNORE and ERROR_FOR_NULL and save/restores check-field options. mysql-test/r/trigger.result: Show that UPDATE...SET...NULL on NOT NULL columns doesn't behave differently when run after a trigger. mysql-test/t/trigger.test: Show that UPDATE...SET...NULL on NOT NULL columns doesn't behave differently when run after a trigger. sql/field_conv.cc: CHECK_FIELD_IGNORE was treated as CHECK_FIELD_ERROR_FOR_NULL. Distinguish between the two. sql/sp_head.cc: raise error as needed sql/sql_class.cc: Save and restore check-fields options. sql/sql_class.h: Make room so we can save check-fields options. sql/sql_insert.cc: raise error as needed --- sql/field_conv.cc | 26 ++++++++++++++++++-------- sql/sp_head.cc | 1 + sql/sql_class.cc | 4 ++++ sql/sql_class.h | 1 + sql/sql_insert.cc | 2 +- 5 files changed, 25 insertions(+), 9 deletions(-) (limited to 'sql') diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 3574534722e..0bffde9671a 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -122,13 +122,18 @@ set_field_to_null(Field *field) return 0; } field->reset(); - if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN) - { + switch (field->table->in_use->count_cuted_fields) { + case CHECK_FIELD_WARN: field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + /* fall through */ + case CHECK_FIELD_IGNORE: return 0; + case CHECK_FIELD_ERROR_FOR_NULL: + if (!field->table->in_use->no_errors) + my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + return -1; } - if (!field->table->in_use->no_errors) - my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + DBUG_ASSERT(0); // impossible return -1; } @@ -178,13 +183,18 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions) field->table->auto_increment_field_not_null= FALSE; return 0; // field is set in fill_record() } - if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN) - { + switch (field->table->in_use->count_cuted_fields) { + case CHECK_FIELD_WARN: field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_BAD_NULL_ERROR, 1); + /* fall through */ + case CHECK_FIELD_IGNORE: return 0; + case CHECK_FIELD_ERROR_FOR_NULL: + if (!field->table->in_use->no_errors) + my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + return -1; } - if (!field->table->in_use->no_errors) - my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + DBUG_ASSERT(0); // impossible return -1; } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8a626cabd90..11d5e5f830b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3009,6 +3009,7 @@ int sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) { DBUG_ENTER("sp_instr_set_trigger_field::execute"); + thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 673fc9b78e6..266064f9f08 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3100,6 +3100,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, } #endif + backup->count_cuted_fields= count_cuted_fields; backup->options= options; backup->in_sub_stmt= in_sub_stmt; backup->enable_slow_log= enable_slow_log; @@ -3137,6 +3138,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, void THD::restore_sub_statement_state(Sub_statement_state *backup) { + DBUG_ENTER("THD::restore_sub_statement_state"); #ifndef EMBEDDED_LIBRARY /* BUG#33029, if we are replicating from a buggy master, restore auto_inc_intervals_forced so that the top statement can use the @@ -3163,6 +3165,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) /* ha_release_savepoint() never returns error. */ (void)ha_release_savepoint(this, sv); } + count_cuted_fields= backup->count_cuted_fields; transaction.savepoints= backup->savepoints; options= backup->options; in_sub_stmt= backup->in_sub_stmt; @@ -3192,6 +3195,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) */ examined_row_count+= backup->examined_row_count; cuted_fields+= backup->cuted_fields; + DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 032985dc44e..2ddd9358382 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -995,6 +995,7 @@ public: bool enable_slow_log; bool last_insert_id_used; SAVEPOINT *savepoints; + enum enum_check_fields count_cuted_fields; }; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 1f4ca90157f..35c24e7571e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3158,7 +3158,7 @@ bool select_insert::send_data(List &values) thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields store_values(values); - thd->count_cuted_fields= CHECK_FIELD_IGNORE; + thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; if (thd->is_error()) { table->auto_increment_field_not_null= FALSE; -- cgit v1.2.1 From 1fc1f462b6d469d7b1f2bb94ba99f4554ced1cd5 Mon Sep 17 00:00:00 2001 From: "Tatiana A. Nurnberg" Date: Fri, 19 Feb 2010 15:16:43 +0000 Subject: Bug#49487: crash with explain extended and group_concat in a derived table When EXPLAIN EXTENDED tries to print column names, it checks whether the referenced table is CONST (in which case, the column's value rather than its name will be printed). If no proper table is reference (i.e. because a derived table was used that has since gone out of scope), this will fail spectacularly. This ports an equivalent of the fix for Bug 43354. mysql-test/r/func_gconcat.result: Show that EXPLAIN EXTENDED on a GROUP_CONCAT() on a derived table no longer crashes the server. mysql-test/t/func_gconcat.test: Show that EXPLAIN EXTENDED on a GROUP_CONCAT() on a derived table no longer crashes the server. sql/item_sum.cc: Do not de-ref what cannot be, that is, temp-tables that have gone away. This is of questionable utility anyway, since our deref has the sole purpose of checking whether the table is const (in which case, we'll substitute the column with its value in EXPLAIN EXTENDED - that is all). --- sql/item_sum.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_sum.cc b/sql/item_sum.cc index dde8fe29e5a..4c2bde90100 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3538,6 +3538,8 @@ String* Item_func_group_concat::val_str(String* str) void Item_func_group_concat::print(String *str) { + /* orig_args is not filled with valid values until fix_fields() */ + Item **pargs= fixed ? orig_args : args; str->append(STRING_WITH_LEN("group_concat(")); if (distinct) str->append(STRING_WITH_LEN("distinct ")); @@ -3545,7 +3547,7 @@ void Item_func_group_concat::print(String *str) { if (i) str->append(','); - args[i]->print(str); + pargs[i]->print(str); } if (arg_count_order) { -- cgit v1.2.1 From 57a40848848274a83313f0d57bb184307e0ff87b Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Mon, 22 Feb 2010 14:23:47 +0100 Subject: Bug #43414 Parenthesis (and other) warnings compiling MySQL with gcc 4.3.2 This is the final patch in the context of this bug. cmd-line-utils/readline/rlmbutil.h: Changed in a previous patch, reverted by a backport. cmd-line-utils/readline/text.c: Static var initialization. extra/yassl/include/yassl_error.hpp: SetErrorString handles errors outside of the YasslError enum. extra/yassl/src/ssl.cpp: SetErrorString handles errors outside of the YasslError enum. extra/yassl/src/yassl_error.cpp: SetErrorString handles errors outside of the YasslError enum. --- sql/log_event.cc | 2 +- sql/log_event_old.cc | 2 +- sql/sql_update.cc | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index de395f3d4c7..7de986b325b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -8753,7 +8753,7 @@ static bool record_compare(TABLE *table) DBUG_DUMP("record[1]", table->record[1], table->s->reclength); bool result= FALSE; - uchar saved_x[2], saved_filler[2]; + uchar saved_x[2]= {0, 0}, saved_filler[2]= {0, 0}; if (table->s->null_bytes > 0) { diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 313916c9818..0f501fd1514 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -337,7 +337,7 @@ static bool record_compare(TABLE *table) */ bool result= FALSE; - uchar saved_x[2], saved_filler[2]; + uchar saved_x[2]= {0, 0}, saved_filler[2]= {0, 0}; if (table->s->null_bytes > 0) { diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 84610630d62..63af275cef3 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1283,7 +1283,8 @@ bool mysql_multi_update(THD *thd, if (using_handler) { - Internal_error_handler *top_handler= thd->pop_internal_handler(); + Internal_error_handler *top_handler; + top_handler= thd->pop_internal_handler(); DBUG_ASSERT(&handler == top_handler); } -- cgit v1.2.1 From dad7b3c55e2f4da0d3b03e561bea20153b03a720 Mon Sep 17 00:00:00 2001 From: "Tatiana A. Nurnberg" Date: Mon, 22 Feb 2010 16:58:56 +0000 Subject: revert 48525 --- sql/field_conv.cc | 26 ++++++++------------------ sql/sp_head.cc | 1 - sql/sql_class.cc | 4 ---- sql/sql_class.h | 1 - sql/sql_insert.cc | 2 +- 5 files changed, 9 insertions(+), 25 deletions(-) (limited to 'sql') diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 0bffde9671a..3574534722e 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -122,18 +122,13 @@ set_field_to_null(Field *field) return 0; } field->reset(); - switch (field->table->in_use->count_cuted_fields) { - case CHECK_FIELD_WARN: + if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN) + { field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); - /* fall through */ - case CHECK_FIELD_IGNORE: return 0; - case CHECK_FIELD_ERROR_FOR_NULL: - if (!field->table->in_use->no_errors) - my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); - return -1; } - DBUG_ASSERT(0); // impossible + if (!field->table->in_use->no_errors) + my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); return -1; } @@ -183,18 +178,13 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions) field->table->auto_increment_field_not_null= FALSE; return 0; // field is set in fill_record() } - switch (field->table->in_use->count_cuted_fields) { - case CHECK_FIELD_WARN: + if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN) + { field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_BAD_NULL_ERROR, 1); - /* fall through */ - case CHECK_FIELD_IGNORE: return 0; - case CHECK_FIELD_ERROR_FOR_NULL: - if (!field->table->in_use->no_errors) - my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); - return -1; } - DBUG_ASSERT(0); // impossible + if (!field->table->in_use->no_errors) + my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); return -1; } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 11d5e5f830b..8a626cabd90 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3009,7 +3009,6 @@ int sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) { DBUG_ENTER("sp_instr_set_trigger_field::execute"); - thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 266064f9f08..673fc9b78e6 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3100,7 +3100,6 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, } #endif - backup->count_cuted_fields= count_cuted_fields; backup->options= options; backup->in_sub_stmt= in_sub_stmt; backup->enable_slow_log= enable_slow_log; @@ -3138,7 +3137,6 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, void THD::restore_sub_statement_state(Sub_statement_state *backup) { - DBUG_ENTER("THD::restore_sub_statement_state"); #ifndef EMBEDDED_LIBRARY /* BUG#33029, if we are replicating from a buggy master, restore auto_inc_intervals_forced so that the top statement can use the @@ -3165,7 +3163,6 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) /* ha_release_savepoint() never returns error. */ (void)ha_release_savepoint(this, sv); } - count_cuted_fields= backup->count_cuted_fields; transaction.savepoints= backup->savepoints; options= backup->options; in_sub_stmt= backup->in_sub_stmt; @@ -3195,7 +3192,6 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) */ examined_row_count+= backup->examined_row_count; cuted_fields+= backup->cuted_fields; - DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 2ddd9358382..032985dc44e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -995,7 +995,6 @@ public: bool enable_slow_log; bool last_insert_id_used; SAVEPOINT *savepoints; - enum enum_check_fields count_cuted_fields; }; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 35c24e7571e..1f4ca90157f 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3158,7 +3158,7 @@ bool select_insert::send_data(List &values) thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields store_values(values); - thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; + thd->count_cuted_fields= CHECK_FIELD_IGNORE; if (thd->is_error()) { table->auto_increment_field_not_null= FALSE; -- cgit v1.2.1 From 710d571030b9c97fef10968cc217012316106646 Mon Sep 17 00:00:00 2001 From: Magne Mahre Date: Tue, 23 Feb 2010 12:17:20 +0100 Subject: Revert of a change introduced by Bug#47974 "TYPE=storage_engine" is deprecated, and will be removed in the Celosia release of MySQL. Since the option is present in the Betony release and the version number of Celosia is still not decided, we need to bump the deprecation version number back up to "6.0". --- sql/sql_yacc.yy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 37150bf835d..8dc08f8425f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4596,7 +4596,7 @@ create_table_option: | TYPE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; - WARN_DEPRECATED(yythd, "5.4.4", "TYPE=storage_engine", + WARN_DEPRECATED(yythd, "6.0", "TYPE=storage_engine", "'ENGINE=storage_engine'"); Lex->create_info.used_fields|= HA_CREATE_USED_ENGINE; } -- cgit v1.2.1 From 48d65a645ec7962d8d861de050c65c215e827996 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Wed, 24 Feb 2010 19:01:53 +0000 Subject: BUG#51251: Wrong binlogging in case of TRUNCATE For temporary tables that are created with an engine that does not provide the HTON_CAN_RECREATE, the truncate operation is performed resorting to the optimized handler::ha_delete_all_rows method. However, this means that the truncate will share execution path, from mysql_delete, with truncate on regular tables and other delete operations. As a consequence the truncate operation, for the temporary table is logged, even if in row mode because there is no distinction between this and the other delete operations at binlogging time. We fix this by checking if: (i) the binlog format, when the truncate operation was issued, is ROW; (ii) if the operation is a truncate; and (iii) if the table is a temporary table; before writing to the binary log. If all three conditions are met, we skip writing to the binlog. A side effect of this fix is that we limit the scope of setting and resetting the current_stmt_binlog_row_based. Now we just set and reset it inside mysql_delete in the boundaries of the handler::ha_write_row loop. This way we have access to thd->current_stmt_binlog_row_based real value inside mysql_delete. mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result: Updated result for spurious truncate table. mysql-test/suite/binlog/t/binlog_row_innodb_truncate.test: Test case. sql/sql_delete.cc: Added check in mysql_delete before writing the TRUNCATE statement to the binary log. Additionally, removed the set/reset of current_stmt_binlog_row_based so that it happens just in the boundaries of the handler::ha_write_row loop inside mysql_delete. --- sql/sql_delete.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index af3fdf11696..ef4b35486f6 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -50,6 +50,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SELECT_LEX *select_lex= &thd->lex->select_lex; THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_delete"); + bool save_binlog_row_based; THD::enum_binlog_query_type query_type= thd->lex->sql_command == SQLCOM_TRUNCATE ? @@ -293,6 +294,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->mark_columns_needed_for_delete(); + save_binlog_row_based= thd->current_stmt_binlog_row_based; + if (thd->lex->sql_command == SQLCOM_TRUNCATE && + thd->current_stmt_binlog_row_based) + thd->clear_current_stmt_binlog_row_based(); + while (!(error=info.read_record(&info)) && !thd->killed && ! thd->is_error()) { @@ -342,6 +348,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, else table->file->unlock_row(); // Row failed selection, release lock on it } + thd->current_stmt_binlog_row_based= save_binlog_row_based; killed_status= thd->killed; if (killed_status != THD::NOT_KILLED || thd->is_error()) error= 1; // Aborted @@ -390,7 +397,10 @@ cleanup: /* See similar binlogging code in sql_update.cc, for comments */ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { - if (mysql_bin_log.is_open()) + if (mysql_bin_log.is_open() && + !(thd->lex->sql_command == SQLCOM_TRUNCATE && + thd->current_stmt_binlog_row_based && + find_temporary_table(thd, table_list))) { bool const is_trans= thd->lex->sql_command == SQLCOM_TRUNCATE ? @@ -1059,15 +1069,13 @@ bool multi_delete::send_eof() static bool mysql_truncate_by_delete(THD *thd, TABLE_LIST *table_list) { - bool error, save_binlog_row_based= thd->current_stmt_binlog_row_based; + bool error; DBUG_ENTER("mysql_truncate_by_delete"); table_list->lock_type= TL_WRITE; mysql_init_select(thd->lex); - thd->clear_current_stmt_binlog_row_based(); error= mysql_delete(thd, table_list, NULL, NULL, HA_POS_ERROR, LL(0), TRUE); ha_autocommit_or_rollback(thd, error); end_trans(thd, error ? ROLLBACK : COMMIT); - thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(error); } -- cgit v1.2.1 From 9a29bd543e664e87a923e0e1529223cefc6607f9 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Thu, 25 Feb 2010 12:39:43 +0200 Subject: Bug #51089 SHOW STATUS LIKE 'Slave_running' is not compatible with `SHOW SLAVE STATUS' backporting of bug@30703 to 5.1. The fixes are backed up with a regression test. mysql-test/include/test_fieldsize.inc: waiting to stop is to be actually exclusively for SQL thread. mysql-test/suite/rpl/r/rpl_show_slave_running.result: new results file is added. mysql-test/suite/rpl/t/rpl_show_slave_running.test: regression test for bug#30703 is added. sql/mysqld.cc: refining `show status like slave_running' handler to correspond to one of `show slave status'. sql/slave.cc: A dbug-sync point is added to complement the regression test. --- sql/mysqld.cc | 3 ++- sql/slave.cc | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a483b9e2381..c4f459d9581 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -7162,7 +7162,8 @@ static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff) var->type= SHOW_MY_BOOL; pthread_mutex_lock(&LOCK_active_mi); var->value= buff; - *((my_bool *)buff)= (my_bool) (active_mi && active_mi->slave_running && + *((my_bool *)buff)= (my_bool) (active_mi && + active_mi->slave_running == MYSQL_SLAVE_RUN_CONNECT && active_mi->rli.slave_running); pthread_mutex_unlock(&LOCK_active_mi); return 0; diff --git a/sql/slave.cc b/sql/slave.cc index 271b3635cf1..a89ac2e682b 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2557,6 +2557,7 @@ pthread_handler_t handle_slave_io(void *arg) connected: + DBUG_SYNC_POINT("debug_lock.before_get_running_status_yes", 10); // TODO: the assignment below should be under mutex (5.0) mi->slave_running= MYSQL_SLAVE_RUN_CONNECT; thd->slave_net = &mysql->net; -- cgit v1.2.1 From e3d0b6d7929ce7080958086c6f4fca61dd13de2e Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 25 Feb 2010 16:57:15 +0200 Subject: Backport of the fix for bug #49552 to 5.0-bugteam --- sql/sql_parse.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 61c2d70a563..64d6888d772 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4009,9 +4009,9 @@ end_with_restore_list: select_lex->where, 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL, (ORDER *)NULL, - select_lex->options | thd->options | + (select_lex->options | thd->options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | - OPTION_SETUP_TABLES_DONE, + OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT, del_result, unit, select_lex); res|= thd->net.report_error; if (unlikely(res)) -- cgit v1.2.1 From 9201bff16b93743aa1a8bfaeff990daf050a2a8d Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Thu, 25 Feb 2010 18:48:53 +0300 Subject: Bug #50335: Assertion `!(order->used & map)' in eq_ref_table The problem was in an incorrect debug assertion. The expression used in the failing assertion states that when finding references matching ORDER BY expressions, there can be only one reference to a single table. But that does not make any sense, all test cases for this bug are valid examples with multiple identical WHERE expressions referencing the same table which are also present in the ORDER BY list. Fixed by removing the failing assertion. We also have to take care of the 'found' counter so that we count multiple references only once. We rely on this fact later in eq_ref_table(). mysql-test/r/join.result: Added a test case for bug #50335. mysql-test/t/join.test: Added a test case for bug #50335. sql/sql_select.cc: Removing the assertion in eq_ref_table() as it does not make any sense. We also have to take care of the 'found' counter so that we count multiple references only once. We rely on this fact later in eq_ref_table(). --- sql/sql_select.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 52f9aae7a0c..b9f59fac4d6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7028,9 +7028,11 @@ eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab) } if (order) { - found++; - DBUG_ASSERT(!(order->used & map)); - order->used|=map; + if (!(order->used & map)) + { + found++; + order->used|= map; + } continue; // Used in ORDER BY } if (!only_eq_ref_tables(join,start_order, (*ref_item)->used_tables())) -- cgit v1.2.1 From 53e8dc26ef90f4170d5fd8b6c2ec30022d1b7c1a Mon Sep 17 00:00:00 2001 From: Christopher Powers Date: Thu, 25 Feb 2010 09:49:09 -0600 Subject: Bug #48739 MySQL crashes on specific INTERVAL in select query Fixed crash caused by x64 int/long incompatibility introduced in Bug #29125. sql/item_timefunc.cc: Fixed crash caused by int/long incompatibility on x64 systems. Changed two "uint" casts and a "long" declartion to "int" in order to ensure that the integer sign is preserved. See Bug #48739 for details. --- sql/item_timefunc.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index de76f821795..d582f26d46c 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -379,7 +379,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, if (tmp - val > 6) tmp= (char*) val + 6; l_time->second_part= (int) my_strtoll10(val, &tmp, &error); - frac_part= 6 - (uint) (tmp - val); + frac_part= 6 - (int) (tmp - val); if (frac_part > 0) l_time->second_part*= (ulong) log_10_int[frac_part]; val= tmp; @@ -870,7 +870,7 @@ static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs, value= value*LL(10) + (longlong) (*str - '0'); if (transform_msec && i == count - 1) // microseconds always last { - long msec_length= 6 - (uint) (str - start); + long msec_length= 6 - (int) (str - start); if (msec_length > 0) value*= (long) log_10_int[msec_length]; } -- cgit v1.2.1 From 936ed6ca86633a91976fd6fcd931683ec007f440 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Thu, 25 Feb 2010 23:13:11 +0400 Subject: Bug #45360: wrong results Propagation of a large unsigned numeric constant in the WHERE expression led to wrong result. For example, "WHERE a = CAST(0xFFFFFFFFFFFFFFFF AS USIGNED) AND FOO(a)", where a is an UNSIGNED BIGINT, and FOO() accepts strings, was transformed to "... AND FOO('-1')". That has been fixed. Also EXPLAIN EXTENDED printed incorrect numeric constants in transformed WHERE expressions like above. That has been fixed too. mysql-test/r/bigint.result: Added test case for bug #45360. mysql-test/t/bigint.test: Added test case for bug #45360. sql/item.cc: Bug #45360: wrong results As far as Item_int_with_ref (and underlaying Item_int) class accepts both signed and unsigned 64bit values, Item_int::val_str and Item_int::print methods have been modified to take into account unsigned_flag. --- sql/item.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index f8cca3a0667..934e897f923 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2209,14 +2209,14 @@ String *Item_int::val_str(String *str) { // following assert is redundant, because fixed=1 assigned in constructor DBUG_ASSERT(fixed == 1); - str->set(value, &my_charset_bin); + str->set_int(value, unsigned_flag, &my_charset_bin); return str; } void Item_int::print(String *str, enum_query_type query_type) { // my_charset_bin is good enough for numbers - str_value.set(value, &my_charset_bin); + str_value.set_int(value, unsigned_flag, &my_charset_bin); str->append(str_value); } -- cgit v1.2.1 From 2d4db52edac1488c9481b303095229b424288e64 Mon Sep 17 00:00:00 2001 From: Evgeny Potemkin Date: Fri, 26 Feb 2010 14:17:00 +0300 Subject: Bug#50843: Filesort used instead of clustered index led to performance degradation. Filesort + join cache combination is preferred to full index scan because it is usually faster. But it's not the case when the index is clustered one. Now test_if_skip_sort_order function prefers filesort only if index isn't clustered. mysql-test/r/innodb_mysql.result: Added a test case for the bug#50843. mysql-test/t/innodb_mysql.test: Added a test case for the bug#50843. sql/sql_select.cc: Bug#50843: Filesort used instead of clustered index led to performance degradation. Now test_if_skip_sort_order function prefers filesort only if index isn't clustered. --- sql/sql_select.cc | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 52f9aae7a0c..c4fac5b50ef 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13304,12 +13304,6 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, */ if (select_limit >= table_records) { - /* - filesort() and join cache are usually faster than reading in - index order and not using join cache - */ - if (tab->type == JT_ALL && tab->join->tables > tab->join->const_tables + 1) - DBUG_RETURN(0); keys= *table->file->keys_to_use_for_scanning(); keys.merge(table->covering_keys); @@ -13459,6 +13453,19 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, } } } + + /* + filesort() and join cache are usually faster than reading in + index order and not using join cache, except in case that chosen + index is clustered primary key. + */ + if ((select_limit >= table_records) && + (tab->type == JT_ALL && + tab->join->tables > tab->join->const_tables + 1) && + ((unsigned) best_key != table->s->primary_key || + !table->file->primary_key_is_clustered())) + DBUG_RETURN(0); + if (best_key >= 0) { bool quick_created= FALSE; -- cgit v1.2.1 From 9245ed4a12ce25214d60f93cbf20882cb2b78741 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 26 Feb 2010 15:39:25 +0400 Subject: Bug#50995 Having clause on subquery result produces incorrect results. The problem is that cond->fix_fields(thd, 0) breaks condition(cuts off 'having'). The reason of that is that NULL valued Item pointer is present in the middle of Item list and it breaks the Item processing loop. mysql-test/r/having.result: test case mysql-test/t/having.test: test case sql/item_cmpfunc.h: added ASSERT to make sure that we do not add NULL valued Item pointer sql/sql_select.cc: skip adding an item to condition if Item pointer is NULL. skip adding a list to condition if this list is empty. --- sql/item_cmpfunc.h | 18 +++++++++++++++--- sql/sql_select.cc | 8 +++++--- 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 38025ff0af5..425f54fb079 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1474,9 +1474,21 @@ public: Item_cond(THD *thd, Item_cond *item); Item_cond(List &nlist) :Item_bool_func(), list(nlist), abort_on_null(0) {} - bool add(Item *item) { return list.push_back(item); } - bool add_at_head(Item *item) { return list.push_front(item); } - void add_at_head(List *nlist) { list.prepand(nlist); } + bool add(Item *item) + { + DBUG_ASSERT(item); + return list.push_back(item); + } + bool add_at_head(Item *item) + { + DBUG_ASSERT(item); + return list.push_front(item); + } + void add_at_head(List *nlist) + { + DBUG_ASSERT(nlist->elements); + list.prepand(nlist); + } bool fix_fields(THD *, Item **ref); enum Type type() const { return COND_ITEM; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b9f59fac4d6..1d88343ad6d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8200,7 +8200,8 @@ static Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels, else { DBUG_ASSERT(cond->type() == Item::COND_ITEM); - ((Item_cond *) cond)->add_at_head(&eq_list); + if (eq_list.elements) + ((Item_cond *) cond)->add_at_head(&eq_list); } cond->quick_fix_field(); @@ -15657,7 +15658,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) Item_cond_and *cond=new Item_cond_and(); TABLE *table=join_tab->table; - int error; + int error= 0; if (!cond) DBUG_RETURN(TRUE); @@ -15675,7 +15676,8 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) cond->fix_fields(thd, (Item**)&cond); if (join_tab->select) { - error=(int) cond->add(join_tab->select->cond); + if (join_tab->select->cond) + error=(int) cond->add(join_tab->select->cond); join_tab->select_cond=join_tab->select->cond=cond; } else if ((join_tab->select= make_select(join_tab->table, 0, 0, cond, 0, -- cgit v1.2.1 From 8713ccb969f3528726b57b0f00711eedf6713a45 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Fri, 26 Feb 2010 12:58:33 +0000 Subject: BUG#51251: Wrong binlogging in case of TRUNCATE Incremental commit based on previous patch. Addresses reviewer comments to move reseting of thd->current_stmt_binlog_row_based to after binlog_query takes place. --- sql/sql_delete.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index ef4b35486f6..7e91a37257b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -148,12 +148,14 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, query_type= THD::STMT_QUERY_TYPE; error= -1; // ok deleted= maybe_deleted; + save_binlog_row_based= thd->current_stmt_binlog_row_based; goto cleanup; } if (error != HA_ERR_WRONG_COMMAND) { table->file->print_error(error,MYF(0)); error=0; + save_binlog_row_based= thd->current_stmt_binlog_row_based; goto cleanup; } /* Handler didn't support fast delete; Delete rows one by one */ @@ -348,7 +350,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, else table->file->unlock_row(); // Row failed selection, release lock on it } - thd->current_stmt_binlog_row_based= save_binlog_row_based; killed_status= thd->killed; if (killed_status != THD::NOT_KILLED || thd->is_error()) error= 1; // Aborted @@ -434,6 +435,7 @@ cleanup: if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table); free_underlaid_joins(thd, select_lex); if (error < 0 || -- cgit v1.2.1 From ca6691533a7e2a454bbb614583a0058bf7acd2d2 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 26 Feb 2010 17:40:01 +0400 Subject: Bug#47669 Query showed by EXPLAIN EXTENDED gives different result from original query Item_field::print method does not take into account fields whose values may be null. The fix is to print 'NULL' if field value is null. mysql-test/r/explain.result: test case mysql-test/r/func_str.result: result fix mysql-test/r/having.result: result fix mysql-test/r/select.result: result fix mysql-test/r/subselect.result: result fix mysql-test/r/union.result: result fix mysql-test/t/explain.test: test case sql/item.cc: print 'NULL' if field value is null. --- sql/item.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 934e897f923..04496338b8f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5690,9 +5690,14 @@ void Item_field::print(String *str, enum_query_type query_type) char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),str->charset()); field->val_str(&tmp); - str->append('\''); - str->append(tmp); - str->append('\''); + if (field->is_null()) + str->append("NULL"); + else + { + str->append('\''); + str->append(tmp); + str->append('\''); + } return; } Item_ident::print(str, query_type); -- cgit v1.2.1 From 600a28368916ae07c0694ae090dcba7f2c52b12a Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Fri, 26 Feb 2010 15:30:14 +0100 Subject: Bug #45058 init_available_charsets uses double checked locking A client doing multiple mysql_library_init() and mysql_library_end() calls over the lifetime of the process may experience lost character set data, potentially even a SIGSEGV. This patch reinstates the reloading of character set data when a mysql_library_init() is done after a mysql_library_end(). --- sql/mysqld.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a483b9e2381..122fadf9847 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1287,6 +1287,7 @@ void clean_up(bool print_message) lex_free(); /* Free some memory */ item_create_cleanup(); set_var_free(); + free_charsets(); if (!opt_noacl) { #ifdef HAVE_DLOPEN -- cgit v1.2.1 From 9715539ebd9519ca66e9b803f435878a819d3f99 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Sun, 28 Feb 2010 21:29:19 +0400 Subject: Fix for bug#51304: checksum table gives different results for same data when using bit fields Problem: checksum for BIT fields may be computed incorrectly in some cases due to its storage peculiarity. Fix: convert a BIT field to a string then calculate its checksum. mysql-test/r/myisam.result: Fix for bug#51304: checksum table gives different results for same data when using bit fields - test result. mysql-test/t/myisam.test: Fix for bug#51304: checksum table gives different results for same data when using bit fields - test case. sql/sql_table.cc: Fix for bug#51304: checksum table gives different results for same data when using bit fields - convert BIT fields to strings calculating its checksums as some bits may be saved among NULL bits in the record buffer. --- sql/sql_table.cc | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 871b2f2d552..eb88b1e70a5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7934,22 +7934,28 @@ 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(); - /* - BLOB and VARCHAR have pointers in their field, we must convert - to string; GEOMETRY is implemented on top of BLOB. - */ - if ((field_type == MYSQL_TYPE_BLOB) || - (field_type == MYSQL_TYPE_VARCHAR) || - (field_type == MYSQL_TYPE_GEOMETRY)) - { - String tmp; - f->val_str(&tmp); - row_crc= my_checksum(row_crc, (uchar*) tmp.ptr(), tmp.length()); + + /* + BLOB and VARCHAR have pointers in their field, we must convert + to string; GEOMETRY is implemented on top of BLOB. + BIT may store its data among NULL bits, convert as well. + */ + switch (f->type()) { + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_GEOMETRY: + case MYSQL_TYPE_BIT: + { + String tmp; + f->val_str(&tmp); + row_crc= my_checksum(row_crc, (uchar*) tmp.ptr(), + tmp.length()); + break; + } + default: + row_crc= my_checksum(row_crc, f->ptr, f->pack_length()); + break; } - else - row_crc= my_checksum(row_crc, f->ptr, - f->pack_length()); } crc+= row_crc; -- cgit v1.2.1 From d6678deab8ec0628aa57522705adccaedea5f8cd Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Mon, 1 Mar 2010 14:49:51 +0100 Subject: Bug#49417 some complaints about mysqld --help --verbose output This patch fixes some typos and poorly formulated sentences in the output from mysqld --help --verbose. Some of the problems described in the bug report are already handled by the patch for Bug#49447, and are therefore not included in this patch. --- sql/mysqld.cc | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5638b074e4a..f658a7c8c3c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6077,8 +6077,8 @@ each time the SQL thread starts.", TC_LOG_PAGE_SIZE, 0}, #endif {"log-update", OPT_UPDATE_LOG, - "The update log is deprecated since version 5.0, is replaced by the binary \ -log and this option justs turns on --log-bin instead.", + "The update log is deprecated since version 5.0, is replaced by the binary " + "log and this option just turns on --log-bin instead.", (uchar**) &opt_update_logname, (uchar**) &opt_update_logname, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-warnings", 'W', "Log some not critical warnings to the log file.", @@ -6338,7 +6338,10 @@ thread is in the relay logs.", "Tells the slave thread to not replicate to the specified database. To specify more than one database to ignore, use the directive multiple times, once for each database. This option will not work if you use cross database updates. If you need cross database updates to work, make sure you have 3.23.28 or later, and use replicate-wild-ignore-table=db_name.%. ", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"replicate-ignore-table", OPT_REPLICATE_IGNORE_TABLE, - "Tells the slave thread to not replicate to the specified table. To specify more than one table to ignore, use the directive multiple times, once for each table. This will work for cross-datbase updates, in contrast to replicate-ignore-db.", + "Tells the slave thread to not replicate to the specified table. To specify " + "more than one table to ignore, use the directive multiple times, once for " + "each table. This will work for cross-database updates, in contrast to " + "replicate-ignore-db.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"replicate-rewrite-db", OPT_REPLICATE_REWRITE_DB, "Updates to a database with a different name than the original. Example: replicate-rewrite-db=master_db_name->slave_db_name.", @@ -6360,7 +6363,13 @@ Can't be set to 1 if --log-slave-updates is used.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, // In replication, we may need to tell the other servers how to connect {"report-host", OPT_REPORT_HOST, - "Hostname or IP of the slave to be reported to to the master during slave registration. Will appear in the output of SHOW SLAVE HOSTS. Leave unset if you do not want the slave to register itself with the master. Note that it is not sufficient for the master to simply read the IP of the slave off the socket once the slave connects. Due to NAT and other routing issues, that IP may not be valid for connecting to the slave from the master or other hosts.", + "Hostname or IP of the slave to be reported to the master during slave " + "registration. Will appear in the output of SHOW SLAVE HOSTS. Leave unset " + "if you do not want the slave to register itself with the master. Note that " + "it is not sufficient for the master to simply read the IP of the slave " + "from the socket once the slave connects. Due to NAT and other routing " + "issues, that IP may not be valid for connecting to the slave from the " + "master or other hosts.", (uchar**) &report_host, (uchar**) &report_host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"report-password", OPT_REPORT_PASSWORD, "Undocumented.", @@ -6665,7 +6674,10 @@ log and this option does nothing anymore.", (uchar**) &max_system_variables.keep_files_on_create, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"key_buffer_size", OPT_KEY_BUFFER_SIZE, - "The size of the buffer used for index blocks for MyISAM tables. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.", + "The size of the buffer used for index blocks for MyISAM tables. Increase " + "this to get better index handling (for all reads and multiple writes) to " + "as much as you can afford; 1GB on a 4GB machine that mainly runs MySQL is " + "quite common.", (uchar**) &dflt_key_cache_var.param_buff_size, (uchar**) 0, 0, (GET_ULL | GET_ASK_ADDR), @@ -6836,7 +6848,9 @@ The minimum value for this variable is 4096.", (uchar**) &myisam_mmap_size, (uchar**) &myisam_mmap_size, 0, GET_ULL, REQUIRED_ARG, SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, 0, 1, 0}, {"myisam_repair_threads", OPT_MYISAM_REPAIR_THREADS, - "Number of threads to use when repairing MyISAM tables. The value of 1 disables parallel repair.", + "Specifies whether several threads should be used when repairing MyISAM " + "tables. For values > 1, one thread is used per index. The value of 1 " + "disables parallel repair.", (uchar**) &global_system_variables.myisam_repair_threads, (uchar**) &max_system_variables.myisam_repair_threads, 0, GET_ULONG, REQUIRED_ARG, 1, 1, ULONG_MAX, 0, 1, 0}, -- cgit v1.2.1 From c610e9783aa4474d2b4418f1b3b3685716a83454 Mon Sep 17 00:00:00 2001 From: "Tatiana A. Nurnberg" Date: Tue, 2 Mar 2010 18:00:53 +0000 Subject: Bug#48295: explain extended crash with subquery and ONLY_FULL_GROUP_BY sql If an outer query is broken, a subquery might not even get set up. EXPLAIN EXTENDED did not expect this and merrily tried to de-ref all of the half-setup info. We now catch this case and print as much as we have, as it doesn't cost us anything (doesn't make regular execution slower). backport from 5.1 mysql-test/r/explain.result: Show that EXPLAIN EXTENDED with subquery and illegal out query doesn't crash. Show also that SHOW WARNINGS will render an additional Note in the hope of being, well, helpful. mysql-test/t/explain.test: If we have only half a query for EXPLAIN EXTENDED to print (i.e., incomplete subquery info as outer query is illegal), we should provide the user with as much info as we easily can if they ask for it. What we should not do is crash when they come asking for help, that violates etiquette in some countries. sql/item_subselect.cc: If the sub-query's actually set up, print it. Otherwise, elide. --- sql/item_subselect.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 80fbc2c74d3..1822a7ced56 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -262,9 +262,14 @@ void Item_subselect::update_used_tables() void Item_subselect::print(String *str) { - str->append('('); - engine->print(str); - str->append(')'); + if (engine) + { + str->append('('); + engine->print(str); + str->append(')'); + } + else + str->append("(...)"); } -- cgit v1.2.1 From d13db314ddb15e333151f15ab72e89ed41c42c5d Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Wed, 3 Mar 2010 12:16:18 +0000 Subject: BUG#51226: mysqlbinlog replay: ERROR 1146 when using temp tables + failing statements Implicit DROP event for temporary table is not getting LOG_EVENT_THREAD_SPECIFIC_F flag, because, in the previous executed statement in the same thread, which might even be a failed statement, the thread_specific_used flag is set to FALSE (in mysql_reset_thd_for_next_command) and not set to TRUE before connection is shutdown. This means that implicit DROP event will take the FALSE value from thread_specific_used and will not set LOG_EVENT_THREAD_SPECIFIC_F in the event header. As a consequence, mysqlbinlog will not print the pseudo_thread_id from the DROP event, because one of the requirements for the printout is that this flag is set to TRUE. We fix this by setting thread_specific_used whenever we are binlogging a DROP in close_temporary_tables, and resetting it to its previous value afterward. --- sql/sql_base.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 06e4b1d3e63..9256d3d907f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1515,6 +1515,7 @@ void close_temporary_tables(THD *thd) { if (is_user_table(table)) { + bool save_thread_specific_used= thd->thread_specific_used; my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id; /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); @@ -1544,6 +1545,7 @@ void close_temporary_tables(THD *thd) thd->clear_error(); CHARSET_INFO *cs_save= thd->variables.character_set_client; thd->variables.character_set_client= system_charset_info; + thd->thread_specific_used= TRUE; Query_log_event qinfo(thd, s_query.ptr(), s_query.length() - 1 /* to remove trailing ',' */, 0, FALSE, 0); @@ -1556,6 +1558,7 @@ void close_temporary_tables(THD *thd) "Failed to write the DROP statement for temporary tables to binary log"); } thd->variables.pseudo_thread_id= save_pseudo_thread_id; + thd->thread_specific_used= save_thread_specific_used; } else { -- cgit v1.2.1 From 7768ccbb54114e8ca35287fbcb14615f81a88783 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Thu, 4 Mar 2010 10:18:06 +0000 Subject: BUG#51055: Replication failure on duplicate key + traditional SQL mode When the master was executing in sql_mode='traditional' (which implies that really_abort_on_warning returns TRUE - because of MODE_STRICT_ALL_TABLES), the error code (ER_DUP_ENTRY in the reported case) was not being set in the Query_log_event. Therefore, even if a failure was to be expected when replaying the statement on the slave, a failure would occur, because the Query_log_event was not transporting the expected error code, but 0 instead. This was because when the master was getting the error code to set it in the Query_log_event, the executing thread would be assumed to have been killed: THD::killed==THD::KILL_BAD_DATA. This would make the error code fetch routine not to check thd->main_da.sql_errno(), but instead the thd->killed value. What's more, is that the server would thd->killed value if thd->killed == THD::KILL_BAD_DATA and return 0 instead. So this is a double inconsistency, as the we should not even check thd->killed but rather thd->main_da.sql_errno(). We fix this by extending the condition used to choose whether to check the thd->main_da.sql_errno() or thd->killed, so that it takes into consideration the case when: thd->killed==THD::KILL_BAD_DATA. --- sql/log.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index b7313a988c4..b75650cfec7 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -4679,7 +4679,7 @@ int query_error_code(THD *thd, bool not_killed) { int error; - if (not_killed) + if (not_killed || (thd->killed == THD::KILL_BAD_DATA)) { error= thd->is_error() ? thd->main_da.sql_errno() : 0; -- cgit v1.2.1 From e46d120e8ef7de8660d10a96f8cfee47e8836b53 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Thu, 4 Mar 2010 12:09:09 +0100 Subject: Bug#48229: group by performance issue of partitioned table Problem was block_size on partitioned tables was not set, resulting in keys_per_block was not correct which affects the cost calculation for read time of indexes (including cost for group min/max).Which resulted in a bad optimizer decision. Fixed by setting stats.block_size correctly. mysql-test/r/partition_range.result: Bug#48229: group by performance issue of partitioned table Added result mysql-test/t/partition_range.test: Bug#48229: group by performance issue of partitioned table Added test sql/ha_partition.cc: Bug#48229: group by performance issue of partitioned table Added missing assignment of stats.block_size. --- sql/ha_partition.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index b854e270029..36bd90e3237 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -5053,6 +5053,7 @@ int ha_partition::info(uint flag) file= m_file[handler_instance]; file->info(HA_STATUS_CONST); + stats.block_size= file->stats.block_size; stats.create_time= file->stats.create_time; ref_length= m_ref_length; } -- cgit v1.2.1 From 48d986f5110c3eb3d0211c437ee87d965263c674 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Thu, 4 Mar 2010 12:29:22 +0100 Subject: Bug#50104: Partitioned table with just 1 partion works with fk There was no check for foreign keys when altering partitioned tables. Added check for FK when altering partitioned tables. mysql-test/r/partition_innodb.result: Bug#50104: Partitioned table with just 1 partion works with fk Updated test result mysql-test/t/partition_innodb.test: Bug#50104: Partitioned table with just 1 partion works with fk Added test for adding FK on partitioned tables (both 1 and 2 partitions) sql/sql_partition.cc: Bug#50104: Partitioned table with just 1 partion works with fk Disabled adding foreign key when altering a partitioned table. --- sql/sql_partition.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sql') diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 275115e3cbd..f12194d7771 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4273,6 +4273,12 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, { DBUG_ENTER("prep_alter_part_table"); + /* Foreign keys on partitioned tables are not supported, waits for WL#148 */ + if (table->part_info && (alter_info->flags & ALTER_FOREIGN_KEY)) + { + my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0)); + DBUG_RETURN(TRUE); + } /* We are going to manipulate the partition info on the table object so we need to ensure that the data structure of the table object -- cgit v1.2.1 From 63a88e137365c4158e22c1c8aba7847b5a0ffe86 Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Fri, 5 Mar 2010 23:45:55 +0400 Subject: Bug #39653: find_shortest_key in sql_select.cc does not consider clustered primary keys Choosing a shortest index for the covering index scan, the optimizer ignored the fact, that the clustered primary key read involves whole table data. The find_shortest_key function has been modified to take into account that fact that a clustered PK has a longest key of possible covering indices. mysql-test/r/innodb_mysql.result: Test case for bug #39653. mysql-test/t/innodb_mysql.test: Test case for bug #39653. sql/sql_select.cc: Bug #39653: find_shortest_key in sql_select.cc does not consider clustered primary keys The find_shortest_key function has been modified to take into account that fact that a clustered PK has a longest key of possible covering indices. --- sql/sql_select.cc | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 773aa7da139..bc68d3b03e0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12912,12 +12912,35 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, uint find_shortest_key(TABLE *table, const key_map *usable_keys) { - uint min_length= (uint) ~0; uint best= MAX_KEY; + uint usable_clustered_pk= (table->file->primary_key_is_clustered() && + table->s->primary_key != MAX_KEY && + usable_keys->is_set(table->s->primary_key)) ? + table->s->primary_key : MAX_KEY; if (!usable_keys->is_clear_all()) { + uint min_length= (uint) ~0; for (uint nr=0; nr < table->s->keys ; nr++) { + /* + As far as + 1) clustered primary key entry data set is a set of all record + fields (key fields and not key fields) and + 2) secondary index entry data is a union of its key fields and + primary key fields (at least InnoDB and its derivatives don't + duplicate primary key fields there, even if the primary and + the secondary keys have a common subset of key fields), + then secondary index entry data is always a subset of primary key + entry, and the PK is always longer. + Unfortunately, key_info[nr].key_length doesn't show the length + of key/pointer pair but a sum of key field lengths only, thus + we can't estimate index IO volume comparing only this key_length + value of seconday keys and clustered PK. + So, try secondary keys first, and choose PK only if there are no + usable secondary covering keys: + */ + if (nr == usable_clustered_pk) + continue; if (usable_keys->is_set(nr)) { if (table->key_info[nr].key_length < min_length) @@ -12928,7 +12951,7 @@ uint find_shortest_key(TABLE *table, const key_map *usable_keys) } } } - return best; + return best != MAX_KEY ? best : usable_clustered_pk; } /** -- cgit v1.2.1 From 1f77c7b49a976026522aba4ff766702b7a76346d Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Thu, 4 Mar 2010 18:16:10 +0100 Subject: Bug#50392: insert_id is not reset for partitioned tables auto_increment on duplicate entry The bug was that when INSERT_ID was used and the storage engine was told to release any reserved but not used auto_increment values, it set the highest auto_increment value to INSERT_ID. The fix was to check if the auto_increment value was forced by user (INSERT_ID) or by slave-thread, i.e. not auto- generated. So that it is only allowed to release generated values. mysql-test/r/partition_error.result: Bug#50392: insert_id is not reset for partitioned tables auto_increment on duplicate entry updated result mysql-test/suite/parts/inc/partition_auto_increment.inc: Bug#50392: insert_id is not reset for partitioned tables auto_increment on duplicate entry Added test mysql-test/suite/parts/r/partition_auto_increment_archive.result: Bug#50392: insert_id is not reset for partitioned tables auto_increment on duplicate entry Added result, note that archive does only allow increasing auto_increment values mysql-test/suite/parts/r/partition_auto_increment_blackhole.result: Bug#50392: insert_id is not reset for partitioned tables auto_increment on duplicate entry Added result, note that blackhole accepts all inserts :) mysql-test/suite/parts/r/partition_auto_increment_innodb.result: Bug#50392: insert_id is not reset for partitioned tables auto_increment on duplicate entry Added result, note that innodb rolls back inserts on error, but keeps the auto_increment value. mysql-test/suite/parts/r/partition_auto_increment_memory.result: Bug#50392: insert_id is not reset for partitioned tables auto_increment on duplicate entry Added result, note that memory and myisam inserts all rows before the error. mysql-test/suite/parts/r/partition_auto_increment_myisam.result: Bug#50392: insert_id is not reset for partitioned tables auto_increment on duplicate entry Added result, note that memory and myisam inserts all rows before the error. mysql-test/suite/parts/r/partition_auto_increment_ndb.result: Bug#50392: insert_id is not reset for partitioned tables auto_increment on duplicate entry Added result, note that NDB does not seem to handle INSERT_ID as other engines. (Martin will look into it). mysql-test/t/partition_error.test: Bug#50392: insert_id is not reset for partitioned tables auto_increment on duplicate entry Added test sql/ha_partition.cc: Bug#50392: insert_id is not reset for partitioned tables auto_increment on duplicate entry If the next_insert_id comes from non generated (i.e forced by INSERT_ID or slave-thread) then we cannot lower the reserved auto_increment value, since it have not reserved any values. --- sql/ha_partition.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 1d4290c6ab0..ddeeab56968 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -6454,9 +6454,22 @@ void ha_partition::release_auto_increment() ulonglong next_auto_inc_val; lock_auto_increment(); next_auto_inc_val= ha_data->next_auto_inc_val; + /* + If the current auto_increment values is lower than the reserved + value, and the reserved value was reserved by this thread, + we can lower the reserved value. + */ if (next_insert_id < next_auto_inc_val && auto_inc_interval_for_cur_row.maximum() >= next_auto_inc_val) - ha_data->next_auto_inc_val= next_insert_id; + { + THD *thd= ha_thd(); + /* + Check that we do not lower the value because of a failed insert + with SET INSERT_ID, i.e. forced/non generated values. + */ + if (thd->auto_inc_intervals_forced.maximum() < next_insert_id) + ha_data->next_auto_inc_val= next_insert_id; + } DBUG_PRINT("info", ("ha_data->next_auto_inc_val: %lu", (ulong) ha_data->next_auto_inc_val)); -- cgit v1.2.1 From 02ac873ccfb5deb46533aefd35640a95f51d1c67 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Tue, 9 Mar 2010 18:55:08 -0300 Subject: Bug#51650: crash with user variables and triggers The problem was that bits of the destructive equality propagation optimization weren't being undone after the execution of a stored program. Modifications to the parse tree that are based on transient properties must be undone to enable the re-execution of stored programs. The solution is to cleanup any references to predicates generated by the equality propagation during the execution of a stored program. mysql-test/r/trigger.result: Add test case result for Bug#51650. mysql-test/t/trigger.test: Add test case for Bug#51650. sql/item.cc: Remove reference to a equality predicate. --- sql/item.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 04496338b8f..ec4c2e6e662 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4475,6 +4475,7 @@ void Item_field::cleanup() I.e. we can drop 'field'. */ field= result_field= 0; + item_equal= NULL; null_value= FALSE; DBUG_VOID_RETURN; } -- cgit v1.2.1 From f502deac11a36bd070c551725bb0bbb29829e01f Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Tue, 9 Mar 2010 07:36:26 -0300 Subject: Bug#40277: SHOW CREATE VIEW returns invalid SQL The problem is that not all column names retrieved from a SELECT statement can be used as view column names due to length and format restrictions. The server failed to properly check the conformity of those automatically generated column names before storing the final view definition on disk. Since columns retrieved from a SELECT statement can be anything ranging from functions to constants values of any format and length, the solution is to rewrite to a pre-defined format any names that are not acceptable as a view column name. The name is rewritten to "Name_exp_%u" where %u translates to the position of the column. To avoid this conversion scheme, define explict names for the view columns via the column_list clause. Also, aliases are now only generated for top level statements. mysql-test/include/view_alias.inc: Add test case for Bug#40277 mysql-test/r/compare.result: Bug#40277: SHOW CREATE VIEW returns invalid SQL mysql-test/r/group_by.result: Bug#40277: SHOW CREATE VIEW returns invalid SQL mysql-test/r/ps.result: Bug#40277: SHOW CREATE VIEW returns invalid SQL mysql-test/r/subselect.result: Bug#40277: SHOW CREATE VIEW returns invalid SQL mysql-test/r/subselect3.result: Bug#40277: SHOW CREATE VIEW returns invalid SQL mysql-test/r/type_datetime.result: Bug#40277: SHOW CREATE VIEW returns invalid SQL mysql-test/r/union.result: Bug#40277: SHOW CREATE VIEW returns invalid SQL mysql-test/r/view.result: Add test case result for Bug#40277 mysql-test/r/view_alias.result: Add test case result for Bug#40277 mysql-test/t/view_alias.test: Add test case for Bug#40277 sql/sql_view.cc: Check if auto generated column names are conforming. Also, the make_unique_view_field_name function is not used as it uses the original name to construct a new one, which does not work if the name is invalid. --- sql/sql_select.cc | 12 +++++++++++- sql/sql_view.cc | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index bc68d3b03e0..2be706cb55e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -16950,7 +16950,17 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) first= 0; else str->append(','); - item->print_item_w_name(str, query_type); + + if (master_unit()->item && item->is_autogenerated_name) + { + /* + Do not print auto-generated aliases in subqueries. It has no purpose + in a view definition or other contexts where the query is printed. + */ + item->print(str, query_type); + } + else + item->print_item_w_name(str, query_type); } /* diff --git a/sql/sql_view.cc b/sql/sql_view.cc index c66990c54c6..5ec80dfb621 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -155,6 +155,35 @@ err: DBUG_RETURN(TRUE); } + +/** + Check if auto generated column names are conforming and + possibly generate a conforming name for them if not. + + @param item_list List of Items which should be checked +*/ + +static void make_valid_column_names(List &item_list) +{ + Item *item; + uint name_len; + List_iterator_fast it(item_list); + char buff[NAME_LEN]; + DBUG_ENTER("make_valid_column_names"); + + for (uint column_no= 1; (item= it++); column_no++) + { + if (!item->is_autogenerated_name || !check_column_name(item->name)) + continue; + name_len= my_snprintf(buff, NAME_LEN, "Name_exp_%u", column_no); + item->orig_name= item->name; + item->set_name(buff, name_len, system_charset_info); + } + + DBUG_VOID_RETURN; +} + + /* Fill defined view parts @@ -548,6 +577,9 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, } } + /* Check if the auto generated column names are conforming. */ + make_valid_column_names(select_lex->item_list); + if (check_duplicate_names(select_lex->item_list, 1)) { res= TRUE; -- cgit v1.2.1 From e1addb0540310ed44586920907ccc2c0d9b1f5f3 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 9 Mar 2010 14:19:10 +0400 Subject: Bug#51377 Crash in information_schema / processlist on concurrent DDL workload the fill_schema_processlist function accesses THD::query() without proper protection so the parallel thread killing can lead to access to the freed meemory. per-file comments: sql/sql_load.cc Bug#51377 Crash in information_schema / processlist on concurrent DDL workload the THD::set_query_inner() call needs to be protected. But here we don't need to change the original thd->query() at all. sql/sql_show.cc Bug#51377 Crash in information_schema / processlist on concurrent DDL workload protect the THD::query() access with the THD::LOCK_thd_data mutex. --- sql/sql_load.cc | 8 +++----- sql/sql_show.cc | 3 +++ 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/sql_load.cc b/sql/sql_load.cc index ee3b442c83a..3fb1b07cf6c 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -689,12 +689,10 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, 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*) fname_start - (char*) thd->query() - 1), - (uint) ((char*) fname_end - (char*) thd->query()), + e(thd, load_data_query, end-load_data_query, + (uint) ((char*) fname_start - load_data_query - 1), + (uint) ((char*) fname_end - load_data_query), (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE : (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR), transactional_table, FALSE, errcode); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 989606300d8..cb60027842d 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1991,6 +1991,8 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) pthread_mutex_unlock(&mysys_var->mutex); /* INFO */ + /* Lock THD mutex that protects its data when looking at it. */ + pthread_mutex_lock(&tmp->LOCK_thd_data); if (tmp->query()) { table->field[7]->store(tmp->query(), @@ -1998,6 +2000,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) tmp->query_length()), cs); table->field[7]->set_notnull(); } + pthread_mutex_unlock(&tmp->LOCK_thd_data); if (schema_table_store_record(thd, table)) { -- cgit v1.2.1 From b8132a8d946bde553834c37785bbe53008f1e925 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 12 Mar 2010 10:33:16 +0400 Subject: Bug#41788 mysql_fetch_field returns org_table == table by a view The problem is that Item_direct_view_ref which is inherited from Item_ident updates orig_table_name and table_name with the same values. The fix is introduction of new constructor into Item_ident and up which updates orig_table_name and table_name separately. mysql-test/r/metadata.result: test case mysql-test/t/metadata.test: test case sql/item.cc: new constructor which updates orig_table_name and table_name separately. sql/item.h: new constructor which updates orig_table_name and table_name separately. sql/table.cc: used new constructor --- sql/item.cc | 26 ++++++++++++++++++++++++++ sql/item.h | 13 +++++++++++++ sql/table.cc | 4 +--- 3 files changed, 40 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index ec4c2e6e662..e34905a2e7f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -556,6 +556,18 @@ Item_ident::Item_ident(Name_resolution_context *context_arg, } +Item_ident::Item_ident(TABLE_LIST *view_arg, const char *field_name_arg) + :orig_db_name(NullS), orig_table_name(view_arg->table_name), + orig_field_name(field_name_arg), context(&view_arg->view->select_lex.context), + db_name(NullS), table_name(view_arg->alias), + field_name(field_name_arg), + alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX), + cached_table(NULL), depended_from(NULL) +{ + name = (char*) field_name_arg; +} + + /** Constructor used by Item_field & Item_*_ref (see Item comment) */ @@ -5721,6 +5733,20 @@ Item_ref::Item_ref(Name_resolution_context *context_arg, } +Item_ref::Item_ref(TABLE_LIST *view_arg, Item **item, + const char *field_name_arg, bool alias_name_used_arg) + :Item_ident(view_arg, field_name_arg), + result_field(NULL), ref(item) +{ + alias_name_used= alias_name_used_arg; + /* + This constructor is used to create some internal references over fixed items + */ + if (ref && *ref && (*ref)->fixed) + set_properties(); +} + + /** Resolve the name of a reference to a column reference. diff --git a/sql/item.h b/sql/item.h index d2e8382023b..77b6e28e98b 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1402,6 +1402,7 @@ public: const char *db_name_arg, const char *table_name_arg, const char *field_name_arg); Item_ident(THD *thd, Item_ident *item); + Item_ident(TABLE_LIST *view_arg, const char *field_name_arg); const char *full_name() const; void cleanup(); bool remove_dependence_processor(uchar * arg); @@ -2222,6 +2223,8 @@ public: Item_ref(Name_resolution_context *context_arg, Item **item, const char *table_name_arg, const char *field_name_arg, bool alias_name_used_arg= FALSE); + Item_ref(TABLE_LIST *view_arg, Item **item, + const char *field_name_arg, bool alias_name_used_arg= FALSE); /* Constructor need to process subselect with temporary tables (see Item) */ Item_ref(THD *thd, Item_ref *item) @@ -2337,6 +2340,12 @@ public: {} /* Constructor need to process subselect with temporary tables (see Item) */ Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {} + Item_direct_ref(TABLE_LIST *view_arg, Item **item, + const char *field_name_arg, + bool alias_name_used_arg= FALSE) + :Item_ref(view_arg, item, field_name_arg, + alias_name_used_arg) + {} double val_real(); longlong val_int(); @@ -2362,6 +2371,10 @@ public: /* Constructor need to process subselect with temporary tables (see Item) */ Item_direct_view_ref(THD *thd, Item_direct_ref *item) :Item_direct_ref(thd, item) {} + Item_direct_view_ref(TABLE_LIST *view_arg, Item **item, + const char *field_name_arg) + :Item_direct_ref(view_arg, item, field_name_arg) + {} bool fix_fields(THD *, Item **); bool eq(const Item *item, bool binary_cmp) const; diff --git a/sql/table.cc b/sql/table.cc index 8758596d408..a4e2c59fb87 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4023,9 +4023,7 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, { DBUG_RETURN(field); } - Item *item= new Item_direct_view_ref(&view->view->select_lex.context, - field_ref, view->alias, - name); + Item *item= new Item_direct_view_ref(view, field_ref, name); DBUG_RETURN(item); } -- cgit v1.2.1 From 81ffd72a5821f07129dedf4c31c3cbc2abfac372 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Tue, 9 Mar 2010 09:16:17 -0300 Subject: Bug#51770: UNINSTALL PLUGIN requires no privileges The problem was that UNINSTALL PLUGIN wasn't performing privilege checks before removing a plugin. Any user (including users without any kind of privileges) could uninstall any plugin. The solution is to verify if the user has the DELETE privilege for the mysql.plugin table before uninstalling a plugin. mysql-test/r/plugin_not_embedded.result: Add test case result for Bug#51770. mysql-test/t/plugin_not_embedded-master.opt: Add example plugin path. mysql-test/t/plugin_not_embedded.test: Add test case for Bug#51770. Skip embedded as test relies on privileges checks. --- sql/sql_plugin.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 9e35e392d2a..0706ef24881 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1736,6 +1736,8 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) bzero(&tables, sizeof(tables)); tables.db= (char *)"mysql"; tables.table_name= tables.alias= (char *)"plugin"; + if (check_table_access(thd, DELETE_ACL, &tables, 1, FALSE)) + DBUG_RETURN(TRUE); /* need to open before acquiring LOCK_plugin or it will deadlock */ if (! (table= open_ltable(thd, &tables, TL_WRITE, 0))) -- cgit v1.2.1 From 7dc693229fc90dbd9c7744435483cbe1a0767c56 Mon Sep 17 00:00:00 2001 From: Martin Hansson Date: Tue, 16 Mar 2010 15:51:00 +0100 Subject: Bug#47762: Incorrect result from MIN() when WHERE tests NOT NULL column for NULL The optimization to read MIN() and MAX() values from an index did not properly handle comparisons with NULL values. Fixed by giving up the particular optimization step if there are non-NULL safe comparisons with NULL values, as the result is NULL anyway. Also, Oracle copyright notice was added to all files. --- sql/field.h | 13 ++++++-- sql/opt_sum.cc | 96 +++++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 75 insertions(+), 34 deletions(-) (limited to 'sql') diff --git a/sql/field.h b/sql/field.h index 55604193687..5bfcc9f21a6 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008, 2009 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -11,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* Because of the function new_field() all field classes that have static @@ -55,7 +55,11 @@ public: static void operator delete(void *ptr_arg, size_t size) { TRASH(ptr_arg, size); } uchar *ptr; // Position to field in record - uchar *null_ptr; // Byte where null_bit is + /** + Byte where the @c NULL bit is stored inside a record. If this Field is a + @c NOT @c NULL field, this member is @c NULL. + */ + uchar *null_ptr; /* Note that you can use table->in_use as replacement for current_thd member only inside of val_*() and store() members (e.g. you can't use it in cons) @@ -261,6 +265,9 @@ public: inline void set_notnull(my_ptrdiff_t row_offset= 0) { if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; } inline bool maybe_null(void) { return null_ptr != 0 || table->maybe_null; } + /** + Signals that this field is NULL-able. + */ inline bool real_maybe_null(void) { return null_ptr != 0; } enum { diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 70d6d0a5b17..8a3fe6c3ae8 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -11,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /** @@ -96,7 +96,7 @@ static ulonglong get_exact_record_count(TABLE_LIST *tables) @param conds WHERE clause @note - This function is only called for queries with sum functions and no + This function is only called for queries with aggregate functions and no GROUP BY part. This means that the result set shall contain a single row only @@ -559,31 +559,57 @@ bool simple_pred(Item_func *func_item, Item **args, bool *inv_order) /** Check whether a condition matches a key to get {MAX|MIN}(field):. - For the index specified by the keyinfo parameter, index that - contains field as its component (field_part), the function - checks whether the condition cond is a conjunction and all its - conjuncts referring to the columns of the same table as column - field are one of the following forms: - - f_i= const_i or const_i= f_i or f_i is null, - where f_i is part of the index - - field {<|<=|>=|>|=} const or const {<|<=|>=|>|=} field - - field between const1 and const2 - - @param[in] max_fl Set to 1 if we are optimising MAX() - @param[in,out] ref Reference to the structure we store the key - value - @param[in] keyinfo Reference to the key info - @param[in] field_part Pointer to the key part for the field - @param[in] cond WHERE condition - @param[in,out] key_part_used Map of matchings parts - @param[in,out] range_fl Says whether including key will be used - @param[out] prefix_len Length of common key part for the range - where MAX/MIN is searched for + For the index specified by the keyinfo parameter and an index that + contains the field as its component (field_part), the function + checks whether + + - the condition cond is a conjunction, + - all of its conjuncts refer to columns of the same table, and + - each conjunct is on one of the following forms: + - f_i = const_i or const_i = f_i or f_i IS NULL, + where f_i is part of the index + - field {<|<=|>=|>|=} const + - const {<|<=|>=|>|=} field + - field BETWEEN const_1 AND const_2 + + As a side-effect, the key value to be used for looking up the MIN/MAX value + is actually stored inside the Field object. An interesting feature is that + the function will find the most restrictive endpoint by over-eager + evaluation of the @c WHERE condition. It continually stores the current + endpoint inside the Field object. For a query such as + + @code + SELECT MIN(a) FROM t1 WHERE a > 3 AND a > 5; + @endcode + + the algorithm will recurse over the conjuction, storing first a 3 in the + field. In the next recursive invocation the expression a > 5 is evaluated + as 3 > 5 (Due to the dual nature of Field objects as value carriers and + field identifiers), which will obviously fail, leading to 5 being stored in + the Field object. + + @param[in] max_fl Set to true if we are optimizing MAX(), + false means we are optimizing %MIN() + @param[in, out] ref Reference to the structure where the function + stores the key value + @param[in] keyinfo Reference to the key info + @param[in] field_part Pointer to the key part for the field + @param[in] cond WHERE condition + @param[in,out] key_part_used Map of matchings parts. The function will output + the set of key parts actually being matched in + this set, yet it relies on the caller to + initialize the value to zero. This is due + to the fact that this value is passed + recursively. + @param[in,out] range_fl Says whether endpoints use strict greater/less + than. + @param[out] prefix_len Length of common key part for the range + where MAX/MIN is searched for @retval - 0 Index can't be used. + false Index can't be used. @retval - 1 We can use index to get MIN/MAX value + true We can use the index to get MIN/MAX value */ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, @@ -620,17 +646,20 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, return 0; // Not operator, can't optimize bool eq_type= 0; // =, <=> or IS NULL + bool is_null_safe_eq= FALSE; // The operator is NULL safe, e.g. <=> bool noeq_type= 0; // < or > bool less_fl= 0; // < or <= - bool is_null= 0; - bool between= 0; + bool is_null= 0; // IS NULL + bool between= 0; // BETWEEN ... AND ... switch (((Item_func*) cond)->functype()) { case Item_func::ISNULL_FUNC: is_null= 1; /* fall through */ case Item_func::EQ_FUNC: + eq_type= TRUE; + break; case Item_func::EQUAL_FUNC: - eq_type= 1; + eq_type= is_null_safe_eq= TRUE; break; case Item_func::LT_FUNC: noeq_type= 1; /* fall through */ @@ -658,6 +687,10 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, if (!simple_pred((Item_func*) cond, args, &inv)) return 0; + if (!is_null_safe_eq && !is_null && + (args[1]->is_null() || (between && args[2]->is_null()))) + return FALSE; + if (inv && !eq_type) less_fl= 1-less_fl; // Convert '<' -> '>' (etc) @@ -708,15 +741,16 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, - field {>|>=} const, when searching for MIN */ - if (is_null) + if (is_null || (is_null_safe_eq && args[1]->is_null())) { part->field->set_null(); *key_ptr= (uchar) 1; } else { - store_val_in_field(part->field, args[between && max_fl ? 2 : 1], - CHECK_FIELD_IGNORE); + /* Update endpoints for MAX/MIN, see function comment. */ + Item *value= args[between && max_fl ? 2 : 1]; + store_val_in_field(part->field, value, CHECK_FIELD_IGNORE); if (part->null_bit) *key_ptr++= (uchar) test(part->field->is_null()); part->field->get_key_image(key_ptr, part->length, Field::itRAW); -- cgit v1.2.1 From ed92f9154966401934712d123d9d9c6e71e00e3c Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Tue, 9 Mar 2010 09:51:56 -0300 Subject: Bug#47761: crash when killing a query during subquery execution... The problem was that killing a query during the optimization phase of a subselect would lead to crashes. The root of the problem is that the subselect execution engine ignores failures (eg: killed) during the optimization phase (JOIN::optimize), leading to a crash once the subquery is executed due to partially initialized structures (in this case a join tab). The optimal solution would be to cleanup certain optimizer structures if the optimization phase fails, but currently there is no infrastructure to properly to track and cleanup the structures. To workaround the whole problem one somewhat good solution is to avoid executing a subselect if the query has been killed. Cutting short any problems caused by failures during the optimization phase. sql/item_subselect.cc: Do not execute a subselect if the session or query has been killed. --- sql/item_subselect.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 26d3833f72c..f89ca2d7955 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -249,9 +249,13 @@ bool Item_subselect::exec() { int res; - if (thd->is_error()) - /* Do not execute subselect in case of a fatal error */ + /* + Do not execute subselect in case of a fatal error + or if the query has been killed. + */ + if (thd->is_error() || thd->killed) return 1; + /* Simulate a failure in sub-query execution. Used to test e.g. out of memory or query being killed conditions. -- cgit v1.2.1 From d63b0a5c62c280d7199157f61d708ff45cb72800 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 9 Mar 2010 17:51:31 +0200 Subject: Bug #35250: readline check breaks when doing vpath build MySQL uses two source layouts when building : the bzr layout and the source package layout. The previous fix for bug 35250 contained 1 change that is valid for both modes and a number of changes that are valid only for the bzr source layout. The important thing was to fix the source package layout. And for this the change in configure.in was sufficient. It's not trivial (and not requested by this bug) to support VPATH builds from the bzr trees. This is why the other changes are reverted and the change to fix the VPATH build for source distributions is left intact. --- sql/share/Makefile.am | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am index 357f9ac0876..68b393e619f 100644 --- a/sql/share/Makefile.am +++ b/sql/share/Makefile.am @@ -22,7 +22,7 @@ dist-hook: test -d $(distdir)/$$dir || mkdir $(distdir)/$$dir; \ $(INSTALL_DATA) $(srcdir)/$$dir/*.* $(distdir)/$$dir; \ done; \ - sleep 1 ; touch $(builddir)/*/errmsg.sys + sleep 1 ; touch $(srcdir)/*/errmsg.sys $(INSTALL_DATA) $(srcdir)/charsets/README $(distdir)/charsets $(INSTALL_DATA) $(srcdir)/charsets/Index.xml $(distdir)/charsets @@ -39,11 +39,11 @@ install-data-local: for lang in @AVAILABLE_LANGUAGES@; \ do \ $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/$$lang; \ - $(INSTALL_DATA) $(builddir)/$$lang/errmsg.sys \ + $(INSTALL_DATA) $(srcdir)/$$lang/errmsg.sys \ $(DESTDIR)$(pkgdatadir)/$$lang/errmsg.sys; \ done $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/charsets - $(INSTALL_DATA) $(builddir)/errmsg.txt \ + $(INSTALL_DATA) $(srcdir)/errmsg.txt \ $(DESTDIR)$(pkgdatadir)/errmsg.txt; \ $(INSTALL_DATA) $(srcdir)/charsets/README $(DESTDIR)$(pkgdatadir)/charsets/README $(INSTALL_DATA) $(srcdir)/charsets/*.xml $(DESTDIR)$(pkgdatadir)/charsets @@ -53,7 +53,7 @@ uninstall-local: @RM@ -f -r $(DESTDIR)$(pkgdatadir) distclean-local: - @RM@ -f $(builddir)/*/errmsg.sys + @RM@ -f */errmsg.sys # Do nothing link_sources: -- cgit v1.2.1 From 405fd822075488597484ef5ce82a8d3296262130 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 10 Mar 2010 15:04:32 +0400 Subject: BUG#51342 - more xid crashing SET autocommit=1 while XA transaction is active may cause various side effects, including memory corruption and server crash. The problem is that SET autocommit=1 and further queries attempt to commit local transaction, whereas XA transaction is still active. As local and XA transactions are mutually exclusive, this patch forbids enabling autocommit mode while XA transaction is active. mysql-test/r/xa.result: A test case for BUG#51342. mysql-test/t/xa.test: A test case for BUG#51342. sql/set_var.cc: Forbid enabling autocommit mode while XA transaction is active. --- sql/set_var.cc | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sql') diff --git a/sql/set_var.cc b/sql/set_var.cc index 4871afd2c56..8e032d44a62 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -3065,6 +3065,13 @@ static bool set_option_autocommit(THD *thd, set_var *var) if ((org_options & OPTION_NOT_AUTOCOMMIT)) { /* We changed to auto_commit mode */ + if (thd->transaction.xid_state.xa_state != XA_NOTR) + { + thd->options= org_options; + my_error(ER_XAER_RMFAIL, MYF(0), + xa_state_names[thd->transaction.xid_state.xa_state]); + return 1; + } thd->options&= ~OPTION_BEGIN; thd->transaction.all.modified_non_trans_table= FALSE; thd->server_status|= SERVER_STATUS_AUTOCOMMIT; -- cgit v1.2.1 From 29b39e7a4423188d99570b290127a74151805ed5 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Wed, 10 Mar 2010 12:56:05 +0100 Subject: Bug#51830: Incorrect partition pruning on range partition (regression) Problem was that partition pruning did not exclude the last partition if the range was beyond it (i.e. not using MAXVALUE) Fix was to not include the last partition if the partitioning function value was not within the partition range. mysql-test/r/partition_innodb.result: Bug#51830: Incorrect partition pruning on range partition (regression) Updated result mysql-test/r/partition_pruning.result: Bug#51830: Incorrect partition pruning on range partition (regression) Updated result mysql-test/t/partition_innodb.test: Bug#51830: Incorrect partition pruning on range partition (regression) Added test for pruning in InnoDB, since it does not show for MyISAM due to 'Impossible WHERE noticed after reading const tables'. mysql-test/t/partition_pruning.test: Bug#51830: Incorrect partition pruning on range partition (regression) Added test sql/sql_partition.cc: Bug#51830: Incorrect partition pruning on range partition (regression) Also increase the partition id if not inside the last partition (and no MAXVALUE is defined). Added comments and DBUG_ASSERT. --- sql/sql_partition.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 275115e3cbd..163d6ae6ba3 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2876,6 +2876,7 @@ int get_partition_id_range(partition_info *part_info, *func_value= part_func_value; if (unsigned_flag) part_func_value-= 0x8000000000000000ULL; + /* Search for the partition containing part_func_value */ while (max_part_id > min_part_id) { loc_part_id= (max_part_id + min_part_id) / 2; @@ -3015,11 +3016,17 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, part_end_val= range_array[loc_part_id]; if (left_endpoint) { + DBUG_ASSERT(part_func_value > part_end_val ? + (loc_part_id == max_partition && + !part_info->defined_max_value) : + 1); /* In case of PARTITION p VALUES LESS THAN MAXVALUE - the maximum value is in the current partition. + the maximum value is in the current (last) partition. + If value is equal or greater than the endpoint, + the range starts from the next partition. */ - if (part_func_value == part_end_val && + if (part_func_value >= part_end_val && (loc_part_id < max_partition || !part_info->defined_max_value)) loc_part_id++; } -- cgit v1.2.1 From c7fad393fd73cc941190fde1b56a2f9e68e9d132 Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Sun, 14 Mar 2010 17:01:45 +0100 Subject: Bug #49829 Many "hides virtual function" warnings with SunStudio SunStudio compilers of late warn about methods that might hide methods in base classes due to the use of overloading combined with overriding. SunStudio also warns about variables defined in local socpe or method arguments that have the same name as a member attribute of the class. This patch renames methods that might hide base class methods, to make it easier both for humans and compilers to see what is actually called. It also renames variables in local scope. sql/field.cc: Local scope variable or method argument same as class attribute. sql/item_cmpfunc.cc: Local scope variable or method argument same as class attribute. sql/item_create.cc: Renaming base class create() to create_func(). sql/item_create.h: Renaming base class create() to create_func(). sql/protocol.cc: Local scope variable or method argument same as class attribute. sql/sql_profile.cc: Local scope variable or method argument same as class attribute. sql/sql_select.cc: Local scope variable or method argument same as class attribute. sql/sql_yacc.yy: Renaming base class create() to create_func(). storage/federated/ha_federated.cc: Local scope variable or method argument same as class attribute. storage/myisammrg/ha_myisammrg.cc: Local scope variable or method argument same as class attribute. --- sql/field.cc | 23 ++++++++-------- sql/item.h | 3 ++- sql/item_cmpfunc.cc | 26 +++++++++--------- sql/item_cmpfunc.h | 4 +-- sql/item_create.cc | 30 ++++++++++----------- sql/item_create.h | 8 +++--- sql/item_sum.cc | 10 +++---- sql/item_sum.h | 6 ++--- sql/log_event_old.cc | 74 ++++++++++++++++++++++++++-------------------------- sql/protocol.cc | 6 ++--- sql/sql_profile.cc | 12 ++++----- sql/sql_select.cc | 12 ++++----- sql/sql_yacc.yy | 6 ++--- 13 files changed, 110 insertions(+), 110 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 15ee9c4a86c..fff6919d88d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2944,16 +2944,16 @@ Field_new_decimal::unpack(uchar* to, a decimal and write that to the raw data buffer. */ decimal_digit_t dec_buf[DECIMAL_MAX_PRECISION]; - decimal_t dec; - dec.len= from_precision; - dec.buf= dec_buf; + decimal_t dec_val; + dec_val.len= from_precision; + dec_val.buf= dec_buf; /* Note: bin2decimal does not change the length of the field. So it is just the first step the resizing operation. The second step does the resizing using the precision and decimals from the slave. */ - bin2decimal((uchar *)from, &dec, from_precision, from_decimal); - decimal2bin(&dec, to, precision, decimals()); + bin2decimal((uchar *)from, &dec_val, from_precision, from_decimal); + decimal2bin(&dec_val, to, precision, decimals()); } else memcpy(to, from, len); // Sizes are the same, just copy the data. @@ -6334,7 +6334,7 @@ check_string_copy_error(Field_str *field, SYNOPSIS Field_longstr::report_if_important_data() - ptr - Truncated rest of string + pstr - Truncated rest of string end - End of truncated string count_spaces - Treat traling spaces as important data @@ -6350,12 +6350,12 @@ check_string_copy_error(Field_str *field, */ int -Field_longstr::report_if_important_data(const char *ptr, const char *end, +Field_longstr::report_if_important_data(const char *pstr, const char *end, bool count_spaces) { - if ((ptr < end) && table->in_use->count_cuted_fields) + if ((pstr < end) && table->in_use->count_cuted_fields) { - if (test_if_important_data(field_charset, ptr, end)) + if (test_if_important_data(field_charset, pstr, end)) { if (table->in_use->abort_on_warning) set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); @@ -7008,9 +7008,8 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16; */ int Field_varstring::do_save_field_metadata(uchar *metadata_ptr) { - char *ptr= (char *)metadata_ptr; DBUG_ASSERT(field_length <= 65535); - int2store(ptr, field_length); + int2store((char*)metadata_ptr, field_length); return 2; } diff --git a/sql/item.h b/sql/item.h index 77b6e28e98b..34416feeb21 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -3028,6 +3028,7 @@ public: Item_cache_int(enum_field_types field_type_arg): Item_cache(field_type_arg), value(0) {} + virtual void store(Item *item){ Item_cache::store(item); } void store(Item *item, longlong val_arg); double val_real(); longlong val_int(); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 1d33e369af0..cd3f18fe1eb 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1022,12 +1022,12 @@ bool Arg_comparator::try_year_cmp_func(Item_result type) @return cache item or original value. */ -Item** Arg_comparator::cache_converted_constant(THD *thd, Item **value, +Item** Arg_comparator::cache_converted_constant(THD *thd_arg, Item **value, Item **cache_item, Item_result type) { /* Don't need cache if doing context analysis only. */ - if (!thd->is_context_analysis_only() && + if (!thd_arg->is_context_analysis_only() && (*value)->const_item() && type != (*value)->result_type()) { Item_cache *cache= Item_cache::get_cache(*value, type); @@ -1368,12 +1368,12 @@ int Arg_comparator::compare_real() int Arg_comparator::compare_decimal() { - my_decimal value1; - my_decimal *val1= (*a)->val_decimal(&value1); + my_decimal decimal1; + my_decimal *val1= (*a)->val_decimal(&decimal1); if (!(*a)->null_value) { - my_decimal value2; - my_decimal *val2= (*b)->val_decimal(&value2); + my_decimal decimal2; + my_decimal *val2= (*b)->val_decimal(&decimal2); if (!(*b)->null_value) { if (set_null) @@ -1397,9 +1397,9 @@ int Arg_comparator::compare_e_real() int Arg_comparator::compare_e_decimal() { - my_decimal value1, value2; - my_decimal *val1= (*a)->val_decimal(&value1); - my_decimal *val2= (*b)->val_decimal(&value2); + my_decimal decimal1, decimal2; + my_decimal *val1= (*a)->val_decimal(&decimal1); + my_decimal *val2= (*b)->val_decimal(&decimal2); if ((*a)->null_value || (*b)->null_value) return test((*a)->null_value && (*b)->null_value); return test(my_decimal_cmp(val1, val2) == 0); @@ -5402,11 +5402,11 @@ void Item_equal::merge(Item_equal *item) members follow in a wrong order they are swapped. This is performed again and again until we get all members in a right order. - @param cmp function to compare field item + @param compare function to compare field item @param arg context extra parameter for the cmp function */ -void Item_equal::sort(Item_field_cmpfunc cmp, void *arg) +void Item_equal::sort(Item_field_cmpfunc compare, void *arg) { bool swap; List_iterator it(fields); @@ -5420,7 +5420,7 @@ void Item_equal::sort(Item_field_cmpfunc cmp, void *arg) while ((item2= it++)) { Item_field **ref2= it.ref(); - if (cmp(item1, item2, arg) < 0) + if (compare(item1, item2, arg) < 0) { Item_field *item= *ref1; *ref1= *ref2; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 425f54fb079..f7d222a47d1 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1616,7 +1616,7 @@ public: longlong val_int(); const char *func_name() const { return "multiple equal"; } optimize_type select_optimize() const { return OPTIMIZE_EQUAL; } - void sort(Item_field_cmpfunc cmp, void *arg); + void sort(Item_field_cmpfunc compare, void *arg); friend class Item_equal_iterator; void fix_length_and_dec(); bool fix_fields(THD *thd, Item **ref); diff --git a/sql/item_create.cc b/sql/item_create.cc index c309ccc06ca..fd8f13d6dc5 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -42,7 +42,7 @@ class Create_native_func : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List *item_list); /** Builder method, with no arguments. @@ -69,7 +69,7 @@ protected: class Create_func_arg0 : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List *item_list); /** Builder method, with no arguments. @@ -93,7 +93,7 @@ protected: class Create_func_arg1 : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List *item_list); /** Builder method, with one argument. @@ -118,7 +118,7 @@ protected: class Create_func_arg2 : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List *item_list); /** Builder method, with two arguments. @@ -144,7 +144,7 @@ protected: class Create_func_arg3 : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List *item_list); /** Builder method, with three arguments. @@ -194,7 +194,7 @@ protected: class Create_func_no_geom : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List *item_list); /** Singleton. */ static Create_func_no_geom s_singleton; @@ -2315,7 +2315,7 @@ static bool has_named_parameters(List *params) Create_func_no_geom Create_func_no_geom::s_singleton; Item* -Create_func_no_geom::create(THD * /* unused */, +Create_func_no_geom::create_func(THD * /* unused */, LEX_STRING /* unused */, List * /* unused */) { @@ -2328,7 +2328,7 @@ Create_func_no_geom::create(THD * /* unused */, Item* -Create_qfunc::create(THD *thd, LEX_STRING name, List *item_list) +Create_qfunc::create_func(THD *thd, LEX_STRING name, List *item_list) { LEX_STRING db; @@ -2361,7 +2361,7 @@ Create_qfunc::create(THD *thd, LEX_STRING name, List *item_list) Create_udf_func Create_udf_func::s_singleton; Item* -Create_udf_func::create(THD *thd, LEX_STRING name, List *item_list) +Create_udf_func::create_func(THD *thd, LEX_STRING name, List *item_list) { udf_func *udf= find_udf(name.str, name.length); DBUG_ASSERT(udf); @@ -2512,7 +2512,7 @@ Create_sp_func::create(THD *thd, LEX_STRING db, LEX_STRING name, Item* -Create_native_func::create(THD *thd, LEX_STRING name, List *item_list) +Create_native_func::create_func(THD *thd, LEX_STRING name, List *item_list) { if (has_named_parameters(item_list)) { @@ -2525,7 +2525,7 @@ Create_native_func::create(THD *thd, LEX_STRING name, List *item_list) Item* -Create_func_arg0::create(THD *thd, LEX_STRING name, List *item_list) +Create_func_arg0::create_func(THD *thd, LEX_STRING name, List *item_list) { int arg_count= 0; @@ -2543,7 +2543,7 @@ Create_func_arg0::create(THD *thd, LEX_STRING name, List *item_list) Item* -Create_func_arg1::create(THD *thd, LEX_STRING name, List *item_list) +Create_func_arg1::create_func(THD *thd, LEX_STRING name, List *item_list) { int arg_count= 0; @@ -2569,7 +2569,7 @@ Create_func_arg1::create(THD *thd, LEX_STRING name, List *item_list) Item* -Create_func_arg2::create(THD *thd, LEX_STRING name, List *item_list) +Create_func_arg2::create_func(THD *thd, LEX_STRING name, List *item_list) { int arg_count= 0; @@ -2597,7 +2597,7 @@ Create_func_arg2::create(THD *thd, LEX_STRING name, List *item_list) Item* -Create_func_arg3::create(THD *thd, LEX_STRING name, List *item_list) +Create_func_arg3::create_func(THD *thd, LEX_STRING name, List *item_list) { int arg_count= 0; diff --git a/sql/item_create.h b/sql/item_create.h index a3ba6bd26a6..d84c764a3d9 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -53,7 +53,7 @@ public: @param item_list The list of arguments to the function, can be NULL @return An item representing the parsed function call, or NULL */ - virtual Item *create(THD *thd, LEX_STRING name, List *item_list) = 0; + virtual Item *create_func(THD *thd, LEX_STRING name, List *item_list) = 0; protected: /** Constructor */ @@ -80,7 +80,7 @@ public: @param item_list The list of arguments to the function, can be NULL @return An item representing the parsed function call */ - virtual Item *create(THD *thd, LEX_STRING name, List *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List *item_list); /** The builder create method, for qualified functions. @@ -127,7 +127,7 @@ extern Create_qfunc * find_qualified_function_builder(THD *thd); class Create_udf_func : public Create_func { public: - virtual Item *create(THD *thd, LEX_STRING name, List *item_list); + virtual Item *create_func(THD *thd, LEX_STRING name, List *item_list); /** The builder create method, for User Defined Functions. diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 142e90639e8..c36fb8b8d64 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -647,7 +647,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) default: DBUG_ASSERT(0); }; - setup(args[0], NULL); + setup_hybrid(args[0], NULL); /* MIN/MAX can return NULL for empty set indepedent of the used column */ maybe_null= 1; unsigned_flag=item->unsigned_flag; @@ -681,7 +681,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) of the original MIN/MAX object and it is saved in this object's cache. */ -void Item_sum_hybrid::setup(Item *item, Item *value_arg) +void Item_sum_hybrid::setup_hybrid(Item *item, Item *value_arg) { value= Item_cache::get_cache(item); value->setup(item); @@ -1651,7 +1651,7 @@ void Item_sum_hybrid::no_rows_in_result() Item *Item_sum_min::copy_or_same(THD* thd) { Item_sum_min *item= new (thd->mem_root) Item_sum_min(thd, this); - item->setup(args[0], value); + item->setup_hybrid(args[0], value); return item; } @@ -1674,7 +1674,7 @@ bool Item_sum_min::add() Item *Item_sum_max::copy_or_same(THD* thd) { Item_sum_max *item= new (thd->mem_root) Item_sum_max(thd, this); - item->setup(args[0], value); + item->setup_hybrid(args[0], value); return item; } diff --git a/sql/item_sum.h b/sql/item_sum.h index f70da52bcd1..5e3972698e9 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -353,7 +353,7 @@ public: */ void no_rows_in_result() { clear(); } - virtual bool setup(THD *thd) {return 0;} + virtual bool setup(THD* thd) {return 0;} virtual void make_unique() {} Item *get_tmp_table_item(THD *thd); virtual Field *create_tmp_field(bool group, TABLE *table, @@ -843,7 +843,7 @@ protected: was_values(item->was_values) { } bool fix_fields(THD *, Item **); - void setup(Item *item, Item *value_arg); + void setup_hybrid(Item *item, Item *value_arg); void clear(); double val_real(); longlong val_int(); diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 0f501fd1514..df162761b35 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -15,7 +15,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info { DBUG_ENTER("Old_rows_log_event::do_apply_event(st_relay_log_info*)"); int error= 0; - THD *thd= ev->thd; + THD *ev_thd= ev->thd; uchar const *row_start= ev->m_rows_buf; /* @@ -33,17 +33,17 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info DBUG_ASSERT(ev->get_flags(Old_rows_log_event::STMT_END_F)); const_cast(rli)->clear_tables_to_lock(); - close_thread_tables(thd); - thd->clear_error(); + close_thread_tables(ev_thd); + ev_thd->clear_error(); DBUG_RETURN(0); } /* - 'thd' has been set by exec_relay_log_event(), just before calling + 'ev_thd' has been set by exec_relay_log_event(), just before calling do_apply_event(). We still check here to prevent future coding errors. */ - DBUG_ASSERT(rli->sql_thd == thd); + DBUG_ASSERT(rli->sql_thd == ev_thd); /* If there is no locks taken, this is the first binrow event seen @@ -51,10 +51,10 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info used in the transaction and proceed with execution of the actual event. */ - if (!thd->lock) + if (!ev_thd->lock) { /* - Lock_tables() reads the contents of thd->lex, so they must be + Lock_tables() reads the contents of ev_thd->lex, so they must be initialized. We also call the mysql_reset_thd_for_next_command(), since this @@ -62,24 +62,24 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info call might reset the value of current_stmt_binlog_row_based, so we need to do any changes to that value after this function. */ - lex_start(thd); - mysql_reset_thd_for_next_command(thd); + lex_start(ev_thd); + mysql_reset_thd_for_next_command(ev_thd); /* Check if the slave is set to use SBR. If so, it should switch to using RBR until the end of the "statement", i.e., next STMT_END_F or next error. */ - if (!thd->current_stmt_binlog_row_based && - mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG)) + if (!ev_thd->current_stmt_binlog_row_based && + mysql_bin_log.is_open() && (ev_thd->options & OPTION_BIN_LOG)) { - thd->set_current_stmt_binlog_row_based(); + ev_thd->set_current_stmt_binlog_row_based(); } - if (simple_open_n_lock_tables(thd, rli->tables_to_lock)) + if (simple_open_n_lock_tables(ev_thd, rli->tables_to_lock)) { - uint actual_error= thd->main_da.sql_errno(); - if (thd->is_slave_error || thd->is_fatal_error) + uint actual_error= ev_thd->main_da.sql_errno(); + if (ev_thd->is_slave_error || ev_thd->is_fatal_error) { /* Error reporting borrowed from Query_log_event with many excessive @@ -87,9 +87,9 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info */ rli->report(ERROR_LEVEL, actual_error, "Error '%s' on opening tables", - (actual_error ? thd->main_da.message() : + (actual_error ? ev_thd->main_da.message() : "unexpected success or fatal error")); - thd->is_slave_error= 1; + ev_thd->is_slave_error= 1; } const_cast(rli)->clear_tables_to_lock(); DBUG_RETURN(actual_error); @@ -109,9 +109,9 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info { if (ptr->m_tabledef.compatible_with(rli, ptr->table)) { - mysql_unlock_tables(thd, thd->lock); - thd->lock= 0; - thd->is_slave_error= 1; + mysql_unlock_tables(ev_thd, ev_thd->lock); + ev_thd->lock= 0; + ev_thd->is_slave_error= 1; const_cast(rli)->clear_tables_to_lock(); DBUG_RETURN(Old_rows_log_event::ERR_BAD_TABLE_DEF); } @@ -159,23 +159,23 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info TIMESTAMP column to a table with one. So we call set_time(), like in SBR. Presently it changes nothing. */ - thd->set_time((time_t)ev->when); + ev_thd->set_time((time_t)ev->when); /* There are a few flags that are replicated with each row event. Make sure to set/clear them before executing the main body of the event. */ if (ev->get_flags(Old_rows_log_event::NO_FOREIGN_KEY_CHECKS_F)) - thd->options|= OPTION_NO_FOREIGN_KEY_CHECKS; + ev_thd->options|= OPTION_NO_FOREIGN_KEY_CHECKS; else - thd->options&= ~OPTION_NO_FOREIGN_KEY_CHECKS; + ev_thd->options&= ~OPTION_NO_FOREIGN_KEY_CHECKS; if (ev->get_flags(Old_rows_log_event::RELAXED_UNIQUE_CHECKS_F)) - thd->options|= OPTION_RELAXED_UNIQUE_CHECKS; + ev_thd->options|= OPTION_RELAXED_UNIQUE_CHECKS; else - thd->options&= ~OPTION_RELAXED_UNIQUE_CHECKS; + ev_thd->options&= ~OPTION_RELAXED_UNIQUE_CHECKS; /* A small test to verify that objects have consistent types */ - DBUG_ASSERT(sizeof(thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS)); + DBUG_ASSERT(sizeof(ev_thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS)); /* Now we are in a statement and will stay in a statement until we @@ -192,7 +192,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info while (error == 0 && row_start < ev->m_rows_end) { uchar const *row_end= NULL; - if ((error= do_prepare_row(thd, rli, table, row_start, &row_end))) + if ((error= do_prepare_row(ev_thd, rli, table, row_start, &row_end))) break; // We should perform the after-row operation even in // the case of error @@ -202,7 +202,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info /* in_use can have been set to NULL in close_tables_for_reopen */ THD* old_thd= table->in_use; if (!table->in_use) - table->in_use= thd; + table->in_use= ev_thd; error= do_exec_row(table); table->in_use = old_thd; switch (error) @@ -216,11 +216,11 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info break; default: - rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), + rli->report(ERROR_LEVEL, ev_thd->main_da.sql_errno(), "Error in %s event: row application failed. %s", ev->get_type_str(), - thd->is_error() ? thd->main_da.message() : ""); - thd->is_slave_error= 1; + ev_thd->is_error() ? ev_thd->main_da.message() : ""); + ev_thd->is_slave_error= 1; break; } @@ -232,7 +232,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info if (!ev->cache_stmt) { DBUG_PRINT("info", ("Marked that we need to keep log")); - thd->options|= OPTION_KEEP_LOG; + ev_thd->options|= OPTION_KEEP_LOG; } } @@ -245,12 +245,12 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info if (error) { /* error has occured during the transaction */ - rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), + rli->report(ERROR_LEVEL, ev_thd->main_da.sql_errno(), "Error in %s event: error during transaction execution " "on table %s.%s. %s", ev->get_type_str(), table->s->db.str, table->s->table_name.str, - thd->is_error() ? thd->main_da.message() : ""); + ev_thd->is_error() ? ev_thd->main_da.message() : ""); /* If one day we honour --skip-slave-errors in row-based replication, and @@ -263,9 +263,9 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info thread is certainly going to stop. rollback at the caller along with sbr. */ - thd->reset_current_stmt_binlog_row_based(); - const_cast(rli)->cleanup_context(thd, error); - thd->is_slave_error= 1; + ev_thd->reset_current_stmt_binlog_row_based(); + const_cast(rli)->cleanup_context(ev_thd, error); + ev_thd->is_slave_error= 1; DBUG_RETURN(error); } diff --git a/sql/protocol.cc b/sql/protocol.cc index 4f69a0fdb52..fad84f8be40 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -525,9 +525,9 @@ void Protocol::init(THD *thd_arg) for the error. */ -void Protocol::end_partial_result_set(THD *thd) +void Protocol::end_partial_result_set(THD *thd_arg) { - net_send_eof(thd, thd->server_status, 0 /* no warnings, we're inside SP */); + net_send_eof(thd_arg, thd_arg->server_status, 0 /* no warnings, we're inside SP */); } diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 8c9b147089f..c661f3744aa 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2007 MySQL AB +/* Copyright (c) 2007, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -485,7 +485,7 @@ void PROFILING::set_query_source(char *query_source_arg, uint query_length_arg) There are two ways to get to this function: Selecting from the information schema, and a SHOW command. */ -int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) +int PROFILING::fill_statistics_info(THD *thd_arg, TABLE_LIST *tables, Item *cond) { DBUG_ENTER("PROFILING::fill_statistics_info"); TABLE *table= tables->table; @@ -520,7 +520,7 @@ int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) /* Skip the first. We count spans of fence, not fence-posts. */ if (previous == NULL) continue; - if (thd->lex->sql_command == SQLCOM_SHOW_PROFILE) + if (thd_arg->lex->sql_command == SQLCOM_SHOW_PROFILE) { /* We got here via a SHOW command. That means that we stored @@ -533,14 +533,14 @@ int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) struct where and having conditions at the SQL layer, then this condition should be ripped out. */ - if (thd->lex->profile_query_id == 0) /* 0 == show final query */ + if (thd_arg->lex->profile_query_id == 0) /* 0 == show final query */ { if (query != last) continue; } else { - if (thd->lex->profile_query_id != query->profiling_query_id) + if (thd_arg->lex->profile_query_id != query->profiling_query_id) continue; } } @@ -661,7 +661,7 @@ int PROFILING::fill_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond) table->field[17]->set_notnull(); } - if (schema_table_store_record(thd, table)) + if (schema_table_store_record(thd_arg, table)) DBUG_RETURN(1); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2be706cb55e..055246ee0df 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -5845,7 +5845,7 @@ store_val_in_field(Field *field, Item *item, enum_check_fields check_flag) @retval TRUE error occurred */ bool -JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table) +JOIN::make_simple_join(JOIN *parent, TABLE *temp_table) { DBUG_ENTER("JOIN::make_simple_join"); @@ -5858,7 +5858,7 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table) DBUG_RETURN(TRUE); /* purecov: inspected */ join_tab= parent->join_tab_reexec; - table= &parent->table_reexec[0]; parent->table_reexec[0]= tmp_table; + table= &parent->table_reexec[0]; parent->table_reexec[0]= temp_table; tables= 1; const_tables= 0; const_table_map= 0; @@ -5878,7 +5878,7 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table) do_send_rows= row_limit ? 1 : 0; join_tab->cache.buff=0; /* No caching */ - join_tab->table=tmp_table; + join_tab->table=temp_table; join_tab->select=0; join_tab->select_cond=0; join_tab->quick=0; @@ -5895,8 +5895,8 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table) join_tab->join= this; join_tab->ref.key_parts= 0; bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record)); - tmp_table->status=0; - tmp_table->null_row=0; + temp_table->status=0; + temp_table->null_row=0; DBUG_RETURN(FALSE); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8dc08f8425f..4f43ab8bebd 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -8013,7 +8013,7 @@ function_call_generic: builder= find_native_function_builder(thd, $1); if (builder) { - item= builder->create(thd, $1, $4); + item= builder->create_func(thd, $1, $4); } else { @@ -8035,7 +8035,7 @@ function_call_generic: { builder= find_qualified_function_builder(thd); DBUG_ASSERT(builder); - item= builder->create(thd, $1, $4); + item= builder->create_func(thd, $1, $4); } } -- cgit v1.2.1 From 9fc32c2e2441d254ec21d5b0541e468f9d9dd149 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Mon, 15 Mar 2010 09:07:16 -0300 Subject: Bug#51289: double Item_cache_decimal::val_real() is broken Fix up function return value, it must return a double. --- sql/item.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index e34905a2e7f..d253e19e068 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7159,7 +7159,7 @@ double Item_cache_decimal::val_real() DBUG_ASSERT(fixed); double res; if (!value_cached && !cache_value()) - return NULL; + return 0.0; my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res); return res; } -- cgit v1.2.1 From 0ed46845479e5d1f995ee6c16cdad7dd4cb43317 Mon Sep 17 00:00:00 2001 From: Martin Hansson Date: Tue, 16 Mar 2010 10:20:07 +0100 Subject: Bug#50918: Date columns treated differently in Views than in Base Tables The type inferrence of a view column caused the result to be interpreted as the wrong type: DATE colums were interpreted as TIME and TIME as DATETIME. This happened because view columns are represented by Item_ref objects as opposed to Item_field's. Item_ref had no method for retrieving a TIME value and thus was forced to depend on the default implementation for any expression, which caused the expression to be evaluated as a string and then parsed into a TIME/DATETIME value. Fixed by letting Item_ref classes forward the request for a TIME value to the referred Item - which is a field in this case - this reads the TIME value directly without conversion. --- sql/item.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index 34416feeb21..d2303853743 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2320,6 +2320,11 @@ public: if (ref && result_type() == ROW_RESULT) (*ref)->bring_value(); } + bool get_time(MYSQL_TIME *ltime) + { + DBUG_ASSERT(fixed); + return (*ref)->get_time(ltime); + } }; -- cgit v1.2.1 From ae49d9710b791d1eaf7f552a44067c5108bd8c85 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 17 Mar 2010 16:18:46 +0200 Subject: Bug #49838: DROP INDEX and ADD UNIQUE INDEX for same index may corrupt definition at engine If a single ALTER TABLE contains both DROP INDEX and ADD INDEX using the same index name (a.k.a. index modification) we need to disable in-place alter table because we can't ask the storage engine to have two copies of the index with the same name even temporarily (if we first do the ADD INDEX and then DROP INDEX) and we can't modify indexes that are needed by e.g. foreign keys if we first do DROP INDEX and then ADD INDEX. Fixed the problem by disabling in-place ALTER TABLE for these cases. --- sql/sql_table.cc | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index eb88b1e70a5..ad72cab664e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5566,6 +5566,45 @@ err: DBUG_RETURN(-1); } +/** + @brief Check if both DROP and CREATE are present for an index in ALTER TABLE + + @details Checks if any index is being modified (present as both DROP INDEX + and ADD INDEX) in the current ALTER TABLE statement. Needed for disabling + online ALTER TABLE. + + @param table The table being altered + @param alter_info The ALTER TABLE structure + @return presence of index being altered + @retval FALSE No such index + @retval TRUE Have at least 1 index modified +*/ + +static bool +is_index_maintenance_unique (TABLE *table, Alter_info *alter_info) +{ + List_iterator key_it(alter_info->key_list); + List_iterator drop_it(alter_info->drop_list); + Key *key; + + while ((key= key_it++)) + { + if (key->name) + { + Alter_drop *drop; + + drop_it.rewind(); + while ((drop= drop_it++)) + { + if (drop->type == Alter_drop::KEY && + !my_strcasecmp(system_charset_info, key->name, drop->name)) + return TRUE; + } + } + } + return FALSE; +} + /* SYNOPSIS @@ -5654,6 +5693,7 @@ compare_tables(TABLE *table, */ Alter_info tmp_alter_info(*alter_info, thd->mem_root); uint db_options= 0; /* not used */ + /* Create the prepared information. */ if (mysql_prepare_create_table(thd, create_info, &tmp_alter_info, @@ -6851,10 +6891,14 @@ view_err: */ new_db_type= create_info->db_type; + if (is_index_maintenance_unique (table, alter_info)) + need_copy_table= ALTER_TABLE_DATA_CHANGED; + if (mysql_prepare_alter_table(thd, table, create_info, alter_info)) goto err; - need_copy_table= alter_info->change_level; + if (need_copy_table == ALTER_TABLE_METADATA_ONLY) + need_copy_table= alter_info->change_level; set_table_default_charset(thd, create_info, db); -- cgit v1.2.1 From 2c5f439d651f00f2f13d1f8e94f3701dadf9c7d3 Mon Sep 17 00:00:00 2001 From: Mats Kindahl Date: Wed, 17 Mar 2010 15:28:49 +0100 Subject: BUG#49618: Field length stored incorrectly in binary log for InnoDB The class Field_bit_as_char stores the metadata for the field incorrecly because bytes_in_rec and bit_len are set to (field_length + 7 ) / 8 and 0 respectively, while Field_bit has the correct values field_length / 8 and field_length % 8. Solved the problem by re-computing the values for the metadata based on the field_length instead of using the bytes_in_rec and bit_len variables. To handle compatibility with old server, a table map flag was added to indicate that the bit computation is exact. If the flag is clear, the slave computes the number of bytes required to store the bit field and compares that instead, effectively allowing replication *without conversion* from any field length that require the same number of bytes to store. mysql-test/suite/rpl/t/rpl_typeconv_innodb.test: Adding test to check compatibility for bit field replication when using InnoDB sql/field.cc: Extending compatible_field_size() with flags from table map to allow fields to check master info. sql/field.h: Extending compatible_field_size() with flags from table map to allow fields to check master info. sql/log.cc: Removing table map flags since they are not used outside table map class. sql/log_event.cc: Removing flags parameter from table map constructor since it is not used and does not have to be exposed. sql/log_event.h: Adding flag to denote that bit length for bit field type is exact and not potentially rounded to even bytes. sql/rpl_utility.cc: Adding fields to table_def to store table map flags. sql/rpl_utility.h: Removing obsolete comment and adding flags to store table map flags from master. --- sql/field.cc | 53 ++++++++++++++++++++++++++++++++++------------------- sql/field.h | 8 ++++---- sql/log.cc | 5 +---- sql/log_event.cc | 10 ++++++---- sql/log_event.h | 10 ++++------ sql/rpl_utility.cc | 2 +- sql/rpl_utility.h | 11 +++-------- 7 files changed, 53 insertions(+), 46 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 354c911e1c0..7c7e334dff1 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1373,12 +1373,14 @@ bool Field::send_binary(Protocol *protocol) to the size of this field (the slave or destination). @param field_metadata Encoded size in field metadata + @param mflags Flags from the table map event for the table. @retval 0 if this field's size is < the source field's size @retval 1 if this field's size is >= the source field's size */ int Field::compatible_field_size(uint field_metadata, - const Relay_log_info *rli_arg __attribute__((unused))) + const Relay_log_info *rli_arg __attribute__((unused)), + uint16 mflags __attribute__((unused))) { uint const source_size= pack_length_from_metadata(field_metadata); uint const destination_size= row_pack_length(); @@ -2836,7 +2838,8 @@ uint Field_new_decimal::pack_length_from_metadata(uint field_metadata) @retval 1 if this field's size is >= the source field's size */ int Field_new_decimal::compatible_field_size(uint field_metadata, - const Relay_log_info * __attribute__((unused))) + const Relay_log_info * __attribute__((unused)), + uint16 mflags __attribute__((unused))) { int compatible= 0; uint const source_precision= (field_metadata >> 8U) & 0x00ff; @@ -6612,7 +6615,8 @@ check_field_for_37426(const void *param_arg) #endif int Field_string::compatible_field_size(uint field_metadata, - const Relay_log_info *rli_arg) + const Relay_log_info *rli_arg, + uint16 mflags __attribute__((unused))) { #ifdef HAVE_REPLICATION const Check_field_param check_param = { this }; @@ -6620,7 +6624,7 @@ int Field_string::compatible_field_size(uint field_metadata, check_field_for_37426, &check_param)) return FALSE; // Not compatible field sizes #endif - return Field::compatible_field_size(field_metadata, rli_arg); + return Field::compatible_field_size(field_metadata, rli_arg, mflags); } @@ -9172,8 +9176,13 @@ uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg) */ int Field_bit::do_save_field_metadata(uchar *metadata_ptr) { - *metadata_ptr= bit_len; - *(metadata_ptr + 1)= bytes_in_rec; + /* + Since this class and Field_bit_as_char have different ideas of + what should be stored here, we compute the values of the metadata + explicitly using the field_length. + */ + metadata_ptr[0]= field_length % 8; + metadata_ptr[1]= field_length / 8; return 2; } @@ -9213,20 +9222,26 @@ uint Field_bit::pack_length_from_metadata(uint field_metadata) @retval 1 if this field's size is >= the source field's size */ int Field_bit::compatible_field_size(uint field_metadata, - const Relay_log_info * __attribute__((unused))) + const Relay_log_info * __attribute__((unused)), + uint16 mflags) { - int compatible= 0; - uint const source_size= pack_length_from_metadata(field_metadata); - uint const destination_size= row_pack_length(); - uint const from_bit_len= field_metadata & 0x00ff; - uint const from_len= (field_metadata >> 8U) & 0x00ff; - if ((bit_len == 0) || (from_bit_len == 0)) - compatible= (source_size <= destination_size); - else if (from_bit_len > bit_len) - compatible= (from_len < bytes_in_rec); - else - compatible= ((from_bit_len <= bit_len) && (from_len <= bytes_in_rec)); - return (compatible); + uint from_bit_len= 8 * (field_metadata >> 8) + (field_metadata & 0xff); + uint to_bit_len= max_display_length(); + + /* + If the bit length exact flag is clear, we are dealing with an old + master, so we allow some less strict behaviour if replicating by + moving both bit lengths to an even multiple of 8. + + We do this by computing the number of bytes to store the field + instead, and then compare the result. + */ + if (!(mflags & Table_map_log_event::TM_BIT_LEN_EXACT_F)) { + from_bit_len= (from_bit_len + 7) / 8; + to_bit_len= (to_bit_len + 7) / 8; + } + + return from_bit_len <= to_bit_len; } diff --git a/sql/field.h b/sql/field.h index 784b9133790..0ed5e6d4cac 100644 --- a/sql/field.h +++ b/sql/field.h @@ -165,7 +165,7 @@ public: */ virtual uint32 pack_length_in_rec() const { return pack_length(); } virtual int compatible_field_size(uint field_metadata, - const Relay_log_info *); + const Relay_log_info *, uint16 mflags); virtual uint pack_length_from_metadata(uint field_metadata) { return field_metadata; } /* @@ -803,7 +803,7 @@ public: uint pack_length_from_metadata(uint field_metadata); uint row_pack_length() { return pack_length(); } int compatible_field_size(uint field_metadata, - const Relay_log_info *rli); + const Relay_log_info *rli, uint16 mflags); uint is_equal(Create_field *new_field); virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data, bool low_byte_first); @@ -1498,7 +1498,7 @@ public: return (((field_metadata >> 4) & 0x300) ^ 0x300) + (field_metadata & 0x00ff); } int compatible_field_size(uint field_metadata, - const Relay_log_info *rli); + const Relay_log_info *rli, uint16 mflags); uint row_pack_length() { return (field_length + 1); } int pack_cmp(const uchar *a,const uchar *b,uint key_length, my_bool insert_or_update); @@ -1962,7 +1962,7 @@ public: uint row_pack_length() { return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); } int compatible_field_size(uint field_metadata, - const Relay_log_info *rli); + const Relay_log_info *rli, uint16 mflags); void sql_type(String &str) const; virtual uchar *pack(uchar *to, const uchar *from, uint max_length, bool low_byte_first); diff --git a/sql/log.cc b/sql/log.cc index 057f5e8cd7d..457be66b87a 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3847,11 +3847,8 @@ int THD::binlog_write_table_map(TABLE *table, bool is_trans) DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open()); DBUG_ASSERT(table->s->table_map_id != ULONG_MAX); - Table_map_log_event::flag_set const - flags= Table_map_log_event::TM_NO_FLAGS; - Table_map_log_event - the_event(this, table, table->s->table_map_id, is_trans, flags); + the_event(this, table, table->s->table_map_id, is_trans); if (is_trans && binlog_table_maps == 0) binlog_start_trans_and_stmt(); diff --git a/sql/log_event.cc b/sql/log_event.cc index 2cb253c9c56..b686aabd36b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -7837,7 +7837,7 @@ int Table_map_log_event::save_field_metadata() */ #if !defined(MYSQL_CLIENT) Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, - bool is_transactional, uint16 flags) + bool is_transactional) : Log_event(thd, 0, true), m_table(tbl), m_dbnam(tbl->s->db.str), @@ -7847,7 +7847,7 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, m_colcnt(tbl->s->fields), m_memory(NULL), m_table_id(tid), - m_flags(flags), + m_flags(TM_BIT_LEN_EXACT_F), m_data_size(0), m_field_metadata(0), m_field_metadata_size(0), @@ -8105,8 +8105,10 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) inside Relay_log_info::clear_tables_to_lock() by calling the table_def destructor explicitly. */ - new (&table_list->m_tabledef) table_def(m_coltype, m_colcnt, - m_field_metadata, m_field_metadata_size, m_null_bits); + new (&table_list->m_tabledef) + table_def(m_coltype, m_colcnt, + m_field_metadata, m_field_metadata_size, + m_null_bits, m_flags); table_list->m_tabledef_valid= TRUE; /* diff --git a/sql/log_event.h b/sql/log_event.h index 31d4a7480c2..673760557ca 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -3283,16 +3283,14 @@ public: /* Special constants representing sets of flags */ enum { - TM_NO_FLAGS = 0U + TM_NO_FLAGS = 0U, + TM_BIT_LEN_EXACT_F = (1U << 0) }; - void set_flags(flag_set flag) { m_flags |= flag; } - void clear_flags(flag_set flag) { m_flags &= ~flag; } flag_set get_flags(flag_set flag) const { return m_flags & flag; } #ifndef MYSQL_CLIENT - Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, - bool is_transactional, uint16 flags); + Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, bool is_transactional); #endif #ifdef HAVE_REPLICATION Table_map_log_event(const char *buf, uint event_len, @@ -3305,7 +3303,7 @@ public: table_def *create_table_def() { return new table_def(m_coltype, m_colcnt, m_field_metadata, - m_field_metadata_size, m_null_bits); + m_field_metadata_size, m_null_bits, m_flags); } ulong get_table_id() const { return m_table_id; } const char *get_table_name() const { return m_tblnam; } diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index e34f8561051..6058c473e9f 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -206,7 +206,7 @@ table_def::compatible_with(Relay_log_info const *rli_arg, TABLE *table) Check the slave's field size against that of the master. */ if (!error && - !field->compatible_field_size(field_metadata(col), rli_arg)) + !field->compatible_field_size(field_metadata(col), rli_arg, m_flags)) { error= 1; char buf[256]; diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 1f4ca246ff1..9f4a4c9454b 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -32,12 +32,6 @@ class Relay_log_info; - Extract and decode table definition data from the table map event - Check if table definition in table map is compatible with table definition on slave - - Currently, the only field type data available is an array of the - type operators that are present in the table map event. - - @todo Add type operands to this structure to allow detection of - difference between, e.g., BIT(5) and BIT(10). */ class table_def @@ -59,9 +53,9 @@ public: @param null_bitmap The bitmap of fields that can be null */ table_def(field_type *types, ulong size, uchar *field_metadata, - int metadata_size, uchar *null_bitmap) + int metadata_size, uchar *null_bitmap, uint16 flags) : m_size(size), m_type(0), m_field_metadata_size(metadata_size), - m_field_metadata(0), m_null_bits(0), m_memory(NULL) + m_field_metadata(0), m_null_bits(0), m_flags(flags), m_memory(NULL) { m_memory= (uchar *)my_multi_malloc(MYF(MY_WME), &m_type, size, @@ -246,6 +240,7 @@ private: uint m_field_metadata_size; uint16 *m_field_metadata; uchar *m_null_bits; + uint16 m_flags; // Table flags uchar *m_memory; }; -- cgit v1.2.1 From caa1ccb0c324bca664112a5562f174f603e0a0b7 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 19 Mar 2010 10:01:02 +0400 Subject: Bug#51494 crash with join, explain and 'sounds like' operator The crash happens because of discrepancy between values of conts_tables and join->const_table_map(make_join_statisctics). Calculation of conts_tables used condition with HA_STATS_RECORDS_IS_EXACT flag check. Calculation of join->const_table_map does not use this flag check. In case of MERGE table without union with index the table does not become const table and thus join_read_const_table() is not called for the table. join->const_table_map supposes this table is const and later in make_join_select this table is used for making&calculation const condition. As table record buffer is not populated it leads to crash. The fix is adding a check if an engine supports HA_STATS_RECORDS_IS_EXACT flag before updating join->const_table_map. mysql-test/r/merge.result: test result mysql-test/t/merge.test: test case sql/sql_select.cc: adding a check if an engine supports HA_STATS_RECORDS_IS_EXACT flag before updating join->const_table_map. --- sql/sql_select.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 055246ee0df..b3640f9dd22 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2943,7 +2943,8 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, s->quick=select->quick; s->needed_reg=select->needed_reg; select->quick=0; - if (records == 0 && s->table->reginfo.impossible_range) + if (records == 0 && s->table->reginfo.impossible_range && + (s->table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT)) { /* Impossible WHERE or ON expression -- cgit v1.2.1 From d1c2e8508fcc795eb5aeafe1af492929ec13ee97 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 19 Mar 2010 10:21:37 +0400 Subject: Bug#51598 Inconsistent behaviour with a COALESCE statement inside an IN comparison Optimizer erroneously translated LEFT JOIN into INNER JOIN. It leads to cutting rows with NULL right side. It happens because Item_row uses not_null_tables() method form the base(Item) class and does not calculate 'null tables' properly. The fix is adding calculation of 'not null tables' to Item_row. mysql-test/r/join_outer.result: test result mysql-test/t/join_outer.test: test case sql/item_row.cc: adding calculation of 'not null tables' to Item_row. sql/item_row.h: adding calculation of 'not null tables' to Item_row. --- sql/item_row.cc | 4 +++- sql/item_row.h | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_row.cc b/sql/item_row.cc index 29b37eb2bc0..7535c1fa80b 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -30,7 +30,8 @@ */ Item_row::Item_row(List &arg): - Item(), used_tables_cache(0), const_item_cache(1), with_null(0) + Item(), used_tables_cache(0), not_null_tables_cache(0), + const_item_cache(1), with_null(0) { //TODO: think placing 2-3 component items in item (as it done for function) @@ -71,6 +72,7 @@ bool Item_row::fix_fields(THD *thd, Item **ref) Item *item= *arg; used_tables_cache |= item->used_tables(); const_item_cache&= item->const_item() && !with_null; + not_null_tables_cache|= item->not_null_tables(); /* Some subqueries transformations aren't done in the view_prepare_mode thus is_null() will fail. So we skip is_null() calculation for CREATE VIEW as diff --git a/sql/item_row.h b/sql/item_row.h index 67441f49603..76d1c875e7d 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -16,7 +16,7 @@ class Item_row: public Item { Item **items; - table_map used_tables_cache; + table_map used_tables_cache, not_null_tables_cache; uint arg_count; bool const_item_cache; bool with_null; @@ -26,6 +26,7 @@ public: Item(), items(item->items), used_tables_cache(item->used_tables_cache), + not_null_tables_cache(0), arg_count(item->arg_count), const_item_cache(item->const_item_cache), with_null(0) @@ -65,6 +66,7 @@ public: bool const_item() const { return const_item_cache; }; enum Item_result result_type() const { return ROW_RESULT; } void update_used_tables(); + table_map not_null_tables() const { return not_null_tables_cache; } virtual void print(String *str, enum_query_type query_type); bool walk(Item_processor processor, bool walk_subquery, uchar *arg); -- cgit v1.2.1 From c3cd608aef94f8b8507997faac9e81eebc32a2d6 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Fri, 19 Mar 2010 11:06:40 +0200 Subject: Bug #51648 DBUG_SYNC_POINT is not defined on all platforms and mtr cant pre-check that DBUG_SYNC_POINT has at least one strong limitation that it's not defined on all platforms. It has issues cooperating with @@debug. All in all its functionality is superseded by DEBUG_SYNC facility and there is no reason to maintain the old less flexible one. Fixed with adding debug_sync_set_action() function as a facility to set up a sync-action in the server sources code and re-writing existing simulations (found 3) to use it. Couple of tests have been reworked as well. The patch offers a pattern for setting sync-points in replication threads where the standard DEBUG_SYNC does not suffice to reach goals. mysql-test/extra/rpl_tests/rpl_get_master_version_and_clock.test: rewriting the test from GET_LOCK()-based to DEBUG_SYNC-based; a pattern of usage DEBUG_SYNC for replication testing is provided. mysql-test/suite/rpl/r/rpl_get_master_version_and_clock.result: results are changed. mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test: rewriting the test from GET_LOCK()-based to DEBUG_SYNC-based; limiting the test to run only with MIXED binlog-format as the test last some 10 secs sensitively contributing to the total of tests run. mysql-test/suite/rpl/t/rpl_show_slave_running.test: rewriting the test from GET_LOCK()-based to DEBUG_SYNC-based. sql/debug_sync.cc: adding debug_sync_set_action() function as a facility to set up a sync-action in the server sources code. sql/debug_sync.h: externalizing debug_sync_set_action(). sql/item_func.cc: purging sources from DBUG_SYNC_POINT. sql/mysql_priv.h: purging sources from DBUG_SYNC_POINT. sql/slave.cc: rewriting failure simulations to base on DEBUG_SYNC rather than GET_LOCK()-based DBUG_SYNC_POINT. sql/sql_repl.cc: removing an orphan failure simulation line because no counterpart in tests existing. --- sql/debug_sync.cc | 38 ++++++++++++++++++++++++++++ sql/debug_sync.h | 1 + sql/item_func.cc | 74 ------------------------------------------------------- sql/mysql_priv.h | 14 ----------- sql/slave.cc | 33 ++++++++++++++++++++++--- sql/sql_repl.cc | 1 - 6 files changed, 69 insertions(+), 92 deletions(-) (limited to 'sql') diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc index 2580d526b52..23a649a89fa 100644 --- a/sql/debug_sync.cc +++ b/sql/debug_sync.cc @@ -1903,4 +1903,42 @@ void debug_sync(THD *thd, const char *sync_point_name, size_t name_len) DBUG_VOID_RETURN; } +/** + Define debug sync action. + + @param[in] thd thread handle + @param[in] action_str action string + + @return status + @retval FALSE ok + @retval TRUE error + + @description + The function is similar to @c debug_sync_eval_action but is + to be called immediately from the server code rather than + to be triggered by setting a value to DEBUG_SYNC system variable. + + @note + The input string is copied prior to be fed to + @c debug_sync_eval_action to let the latter modify it. + + Caution. + The function allocates in THD::mem_root and therefore + is not recommended to be deployed inside big loops. +*/ + +bool debug_sync_set_action(THD *thd, const char *action_str, size_t len) +{ + bool rc; + char *value; + DBUG_ENTER("debug_sync_set_action"); + DBUG_ASSERT(thd); + DBUG_ASSERT(action_str); + + value= strmake_root(thd->mem_root, action_str, len); + rc= debug_sync_eval_action(thd, value); + DBUG_RETURN(rc); +} + + #endif /* defined(ENABLED_DEBUG_SYNC) */ diff --git a/sql/debug_sync.h b/sql/debug_sync.h index f4cd0b364cf..9ac7da39d4d 100644 --- a/sql/debug_sync.h +++ b/sql/debug_sync.h @@ -50,6 +50,7 @@ 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); +extern bool debug_sync_set_action(THD *thd, const char *action_str, size_t len); #else /* defined(ENABLED_DEBUG_SYNC) */ diff --git a/sql/item_func.cc b/sql/item_func.cc index 845654c1881..1e31755179b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3362,80 +3362,6 @@ longlong Item_master_pos_wait::val_int() return event_count; } -#ifdef EXTRA_DEBUG -void debug_sync_point(const char* lock_name, uint lock_timeout) -{ - THD* thd=current_thd; - User_level_lock* ull; - struct timespec abstime; - size_t lock_name_len; - lock_name_len= strlen(lock_name); - pthread_mutex_lock(&LOCK_user_locks); - - if (thd->ull) - { - item_user_lock_release(thd->ull); - thd->ull=0; - } - - /* - If the lock has not been aquired by some client, we do not want to - create an entry for it, since we immediately release the lock. In - this case, we will not be waiting, but rather, just waste CPU and - memory on the whole deal - */ - if (!(ull= ((User_level_lock*) hash_search(&hash_user_locks, - (uchar*) lock_name, - lock_name_len)))) - { - pthread_mutex_unlock(&LOCK_user_locks); - return; - } - ull->count++; - - /* - Structure is now initialized. Try to get the lock. - Set up control struct to allow others to abort locks - */ - thd_proc_info(thd, "User lock"); - thd->mysys_var->current_mutex= &LOCK_user_locks; - thd->mysys_var->current_cond= &ull->cond; - - set_timespec(abstime,lock_timeout); - while (ull->locked && !thd->killed) - { - int error= pthread_cond_timedwait(&ull->cond, &LOCK_user_locks, &abstime); - if (error == ETIMEDOUT || error == ETIME) - break; - } - - if (ull->locked) - { - if (!--ull->count) - delete ull; // Should never happen - } - else - { - ull->locked=1; - ull->set_thread(thd); - thd->ull=ull; - } - pthread_mutex_unlock(&LOCK_user_locks); - pthread_mutex_lock(&thd->mysys_var->mutex); - thd_proc_info(thd, 0); - thd->mysys_var->current_mutex= 0; - thd->mysys_var->current_cond= 0; - pthread_mutex_unlock(&thd->mysys_var->mutex); - pthread_mutex_lock(&LOCK_user_locks); - if (thd->ull) - { - item_user_lock_release(thd->ull); - thd->ull=0; - } - pthread_mutex_unlock(&LOCK_user_locks); -} - -#endif /** Get a user level lock. If the thread has an old lock this is first released. diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 90b02f5337a..098ea514cb6 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -580,20 +580,6 @@ protected: /* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */ #define UNDEF_POS (-1) -#ifdef EXTRA_DEBUG -/** - Sync points allow us to force the server to reach a certain line of code - and block there until the client tells the server it is ok to go on. - The client tells the server to block with SELECT GET_LOCK() - and unblocks it with SELECT RELEASE_LOCK(). Used for debugging difficult - concurrency problems -*/ -#define DBUG_SYNC_POINT(lock_name,lock_timeout) \ - debug_sync_point(lock_name,lock_timeout) -void debug_sync_point(const char* lock_name, uint lock_timeout); -#else -#define DBUG_SYNC_POINT(lock_name,lock_timeout) -#endif /* EXTRA_DEBUG */ /* BINLOG_DUMP options */ diff --git a/sql/slave.cc b/sql/slave.cc index a89ac2e682b..e8405ffcd37 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -44,6 +44,7 @@ #ifdef HAVE_REPLICATION #include "rpl_tblmap.h" +#include "debug_sync.h" #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") @@ -981,7 +982,16 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi) unavailable (very old master not supporting UNIX_TIMESTAMP()?). */ - DBUG_SYNC_POINT("debug_lock.before_get_UNIX_TIMESTAMP", 10); + DBUG_EXECUTE_IF("dbug.before_get_UNIX_TIMESTAMP", + { + const char act[]= + "now " + "wait_for signal.get_unix_timestamp"; + DBUG_ASSERT(opt_debug_sync_timeout > 0); + DBUG_ASSERT(!debug_sync_set_action(current_thd, + STRING_WITH_LEN(act))); + };); + master_res= NULL; if (!mysql_real_query(mysql, STRING_WITH_LEN("SELECT UNIX_TIMESTAMP()")) && (master_res= mysql_store_result(mysql)) && @@ -1020,7 +1030,15 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi) Note: we could have put a @@SERVER_ID in the previous SELECT UNIX_TIMESTAMP() instead, but this would not have worked on 3.23 masters. */ - DBUG_SYNC_POINT("debug_lock.before_get_SERVER_ID", 10); + DBUG_EXECUTE_IF("dbug.before_get_SERVER_ID", + { + const char act[]= + "now " + "wait_for signal.get_server_id"; + DBUG_ASSERT(opt_debug_sync_timeout > 0); + DBUG_ASSERT(!debug_sync_set_action(current_thd, + STRING_WITH_LEN(act))); + };); master_res= NULL; master_row= NULL; if (!mysql_real_query(mysql, @@ -2557,7 +2575,16 @@ pthread_handler_t handle_slave_io(void *arg) connected: - DBUG_SYNC_POINT("debug_lock.before_get_running_status_yes", 10); + DBUG_EXECUTE_IF("dbug.before_get_running_status_yes", + { + const char act[]= + "now " + "wait_for signal.io_thread_let_running"; + DBUG_ASSERT(opt_debug_sync_timeout > 0); + DBUG_ASSERT(!debug_sync_set_action(thd, + STRING_WITH_LEN(act))); + };); + // TODO: the assignment below should be under mutex (5.0) mi->slave_running= MYSQL_SLAVE_RUN_CONNECT; thd->slave_net = &mysql->net; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index ae995ea5ed3..44215d90634 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1711,7 +1711,6 @@ int log_loaded_block(IO_CACHE* file) if (mysql_bin_log.write(&b)) DBUG_RETURN(1); lf_info->wrote_create_file= 1; - DBUG_SYNC_POINT("debug_lock.created_file_event",10); } } DBUG_RETURN(0); -- cgit v1.2.1 From ad6e00e3b2b9bf26805c90cbd7655c6d2b20cab4 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 19 Mar 2010 13:09:22 +0400 Subject: Bug#51242 HAVING clause on table join produce incorrect results The problem is that when we make conditon for grouped result const part of condition is cut off. It happens because some parts of 'having' condition which refer to outer join become const after make_join_statistics. These parts may be lost during further having condition transformation in JOIN::exec. The fix is adding 'having' condition check for const tables after make_join_statistics is performed. mysql-test/r/having.result: test case mysql-test/t/having.test: test result sql/sql_select.cc: added 'having' condition check for const tables after make_join_statistics is performed. --- sql/sql_select.cc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b3640f9dd22..618332ae89b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1112,6 +1112,31 @@ JOIN::optimize() { conds=new Item_int((longlong) 0,1); // Always false } + + /* + It's necessary to check const part of HAVING cond as + there is a chance that some cond parts may become + const items after make_join_statisctics(for example + when Item is a reference to cost table field from + outer join). + This check is performed only for those conditions + which do not use aggregate functions. In such case + temporary table may not be used and const condition + elements may be lost during further having + condition transformation in JOIN::exec. + */ + if (having && !having->with_sum_func) + { + COND *const_cond= make_cond_for_table(having, const_table_map, 0); + DBUG_EXECUTE("where", print_where(const_cond, "const_having_cond", + QT_ORDINARY);); + if (const_cond && !const_cond->val_int()) + { + zero_result_cause= "Impossible HAVING noticed after reading const tables"; + DBUG_RETURN(0); + } + } + if (make_join_select(this, select, conds)) { zero_result_cause= -- cgit v1.2.1 From 8feadddbe437556fe4f8c054fa9c749f77dd20ca Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Mon, 22 Mar 2010 12:33:25 +0400 Subject: Bug #49910: Behavioural change in SELECT/WHERE on YEAR(4) data type (Original patch by Sinisa Milivojevic) The YEAR(4) value of 2000 was equal to the "bad" YEAR(4) value of 0000. The get_year_value() function has been modified to not adjust bad YEAR(4) value to 2000. mysql-test/r/type_year.result: Test case for bug #49910. mysql-test/t/type_year.test: Test case for bug #49910. sql/item_cmpfunc.cc: Bug #49910: Behavioural change in SELECT/WHERE on YEAR(4) data type The get_year_value() function has been modified to not adjust bad YEAR(4) value to 2000. --- sql/item_cmpfunc.cc | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index cd3f18fe1eb..6e38220abd1 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1190,12 +1190,21 @@ get_year_value(THD *thd, Item ***item_arg, Item **cache_arg, /* Coerce value to the 19XX form in order to correctly compare YEAR(2) & YEAR(4) types. + Here we are converting all item values but YEAR(4) fields since + 1) YEAR(4) already has a regular YYYY form and + 2) we don't want to convert zero/bad YEAR(4) values to the + value of 2000. */ - if (value < 70) - value+= 100; - if (value <= 1900) - value+= 1900; - + Item *real_item= item->real_item(); + if (!(real_item->type() == Item::FIELD_ITEM && + ((Item_field *)real_item)->field->type() == MYSQL_TYPE_YEAR && + ((Item_field *)real_item)->field->field_length == 4)) + { + if (value < 70) + value+= 100; + if (value <= 1900) + value+= 1900; + } /* Convert year to DATETIME of form YYYY-00-00 00:00:00 (YYYY0000000000). */ value*= 10000000000LL; -- cgit v1.2.1 From 649ec7758ff0da5355f04d717d57e50fe452e3c0 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Tue, 23 Mar 2010 17:00:50 +0200 Subject: Bug #52304 valgrind does not like to print un-inited string in Protocol_text::store() The reason of the failure was apparent flaw in that a pointer to an uninitialized buffer was passed to DBUG_PRINT of Protocol_text::store(). Fixed with splitting the print-out into two branches: one with length zero of the problematic arg and the rest. sql/protocol.cc: correcting DBUG_PRINT to print out `from' with a care because one may be uninitialized in the caller. --- sql/protocol.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/protocol.cc b/sql/protocol.cc index fad84f8be40..dc53e029647 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -850,7 +850,7 @@ bool Protocol_text::store(const char *from, size_t length, CHARSET_INFO *tocs= this->thd->variables.character_set_results; #ifndef DBUG_OFF DBUG_PRINT("info", ("Protocol_text::store field %u (%u): %s", field_pos, - field_count, from)); + field_count, (length == 0? "" : from))); DBUG_ASSERT(field_pos < field_count); DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || -- cgit v1.2.1 From a9a2ceae1f360c275ed4db5b093ab65be4f5fb7b Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 23 Mar 2010 17:07:00 +0200 Subject: Bug #51850: crash/memory overlap when using load data infile and set col equal to itself! There's no need to copy the value of a field into itself. While generally harmless (except for some performance penalties) it may be dangerous when the copy code doesn't expect this. Fixed by checking if the source field is the same as the destination field before copying the data. Note that we must preserve the order of assignment of the null flags (hence the null_value assignment addition). --- sql/item.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index d253e19e068..809377e80b3 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5063,14 +5063,22 @@ int Item_field::save_in_field(Field *to, bool no_conversions) if (result_field->is_null()) { null_value=1; - res= set_field_to_null_with_conversions(to, no_conversions); + return set_field_to_null_with_conversions(to, no_conversions); } - else + to->set_notnull(); + + /* + If we're setting the same field as the one we're reading from there's + nothing to do. This can happen in 'SET x = x' type of scenarios. + */ + if (to == result_field) { - to->set_notnull(); - res= field_conv(to,result_field); null_value=0; + return 0; } + + res= field_conv(to,result_field); + null_value=0; return res; } -- cgit v1.2.1 From bccf219bfc61bb45d334b40d732651eb9bef5075 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 24 Mar 2010 14:37:28 +0400 Subject: Bug#48483 crash in get_best_combination() The crash happens because greedy_serach can not determine best plan due to wrong inner table dependences. These dependences affects join table sorting which performs before greedy_search starting. In our case table which has real 'no dependences' should be put on top of the list but it does not happen as inner tables have no dependences as well. The fix is to exclude RAND_TABLE_BIT mask from condition which checks if table dependences should be updated. mysql-test/r/join.result: test result mysql-test/t/join.test: test case sql/sql_select.cc: RAND_TABLE_BIT mask should not be counted as it prevents update of inner table dependences. For example it might happen if RAND() function is used in JOIN ON clause. --- sql/sql_select.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index eecc2b086a3..cbc608ea972 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4819,6 +4819,11 @@ greedy_search(JOIN *join, if (best_extension_by_limited_search(join, remaining_tables, idx, record_count, read_time, search_depth, prune_level)) DBUG_RETURN(TRUE); + /* + 'best_read < DBL_MAX' means that optimizer managed to find + some plan and updated 'best_positions' array accordingly. + */ + DBUG_ASSERT(join->best_read < DBL_MAX); if (size_remain <= search_depth) { @@ -8431,8 +8436,14 @@ simplify_joins(JOIN *join, List *join_list, COND *conds, bool top) we still make the inner tables dependent on the outer tables. It would be enough to set dependency only on one outer table for them. Yet this is really a rare case. + Note: + RAND_TABLE_BIT mask should not be counted as it + prevents update of inner table dependences. + For example it might happen if RAND() function + is used in JOIN ON clause. */ - if (!(prev_table->on_expr->used_tables() & ~prev_used_tables)) + if (!((prev_table->on_expr->used_tables() & ~RAND_TABLE_BIT) & + ~prev_used_tables)) prev_table->dep_tables|= used_tables; } } -- cgit v1.2.1 From ea7d830ad2c5715597d2d7e55215263f0fd8ba7c Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Wed, 24 Mar 2010 17:37:41 +0100 Subject: Bug#46615 Assertion in Query_cache::invalidate in INSERT in a VIEW of a MERGE table If the listed columns in the view definition of the table used in a 'INSERT .. SELECT ..' statement mismatched, a debug assertion would trigger in the cache invalidation code following the failing statement. Although the find_field_in_view() function correctly generated ER_BAD_FIELD_ERROR during setup_fields(), the error failed to propagate further than handle_select(). This patch fixes the issue by adding a check for the return value. mysql-test/r/query_cache_with_views.result: * added test for bug 46615 mysql-test/t/query_cache_with_views.test: * added test for bug 46615 sql/sql_parse.cc: * added check for handle_select() return code before attempting to invalidate the cache. --- sql/sql_parse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 168b16c61bf..5228a37f490 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3241,7 +3241,7 @@ end_with_restore_list: TODO: this is workaround. right way will be move invalidating in the unlock procedure. */ - if (first_table->lock_type == TL_WRITE_CONCURRENT_INSERT && + if (!res && first_table->lock_type == TL_WRITE_CONCURRENT_INSERT && thd->lock) { /* INSERT ... SELECT should invalidate only the very first table */ -- cgit v1.2.1 From 412798658a5ede71651ed9112791d055a42edef7 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 25 Mar 2010 16:08:21 +0400 Subject: BUG#51866 - crash with repair by sort and fulltext keys Repairing MyISAM table with fulltext indexes and low myisam_sort_buffer_size may crash the server. Estimation of number of index entries was done incorrectly, causing further assertion failure or server crash. Docs note: min value for myisam_sort_buffer_size has been changed from 4 to 4096. mysql-test/r/fulltext.result: A test case for BUG#51866. mysql-test/r/myisam.result: Min value for myisam_sort_buffer_size is 4096. mysql-test/r/variables.result: Min value for myisam_sort_buffer_size is 4096. mysql-test/suite/sys_vars/r/myisam_sort_buffer_size_basic_32.result: Min value for myisam_sort_buffer_size is 4096. mysql-test/t/fulltext.test: A test case for BUG#51866. sql/mysqld.cc: Min value for myisam_sort_buffer_size is 4096. storage/myisam/mi_check.c: When estimating number of index entries for external fulltext parser, take into account that key_length may be bigger than myisam_sort_buffer_size. Reuse logic from _create_index_by_sort(): force MIN_SORT_BUFFER to be min value for myisam_sort_buffer_size. Another problem is that ftkey_nr has no other meaning than serial number of fulltext index starting with 1. We can't say if this key using built-in or external parser basing on it's value. In other words we always entered if-branch for external parser. At this point, the only way to check if we use default parser is to compare keyinfo::parser with &ft_default_parser. storage/myisam/sort.c: Get rid of MIN_SORT_MEMORY, use MIN_SORT_BUFFER instead (defined in myisamdef.h, has the same value and purpose). --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f658a7c8c3c..bb685ba42e3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6858,7 +6858,7 @@ The minimum value for this variable is 4096.", "The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE.", (uchar**) &global_system_variables.myisam_sort_buff_size, (uchar**) &max_system_variables.myisam_sort_buff_size, 0, - GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0}, + GET_ULONG, REQUIRED_ARG, 8192 * 1024, 4096, ~0L, 0, 1, 0}, {"myisam_use_mmap", OPT_MYISAM_USE_MMAP, "Use memory mapping for reading and writing MyISAM tables.", (uchar**) &opt_myisam_use_mmap, -- cgit v1.2.1 From d5325c7793a640d0f32d62088f84d3d19166add7 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 26 Mar 2010 09:49:35 +0400 Subject: Bug#52164 Assertion failed: param.sort_length, file .\filesort.cc, line 149 The crash happens because of incorrect max_length calculation in QUOTE function(due to overflow). max_length is set to 0 and it leads to assert failure. The fix is to cast expression result to ulonglong variable and adjust it if the result exceeds MAX_BLOB_WIDTH. mysql-test/r/func_str.result: test case mysql-test/t/func_str.test: test case sql/item_strfunc.h: cast expression result to ulonglong variable and adjust it if the result exceeds MAX_BLOB_WIDTH. --- sql/item_strfunc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 5799c768162..aedc63164f2 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -694,8 +694,9 @@ public: String *val_str(String *); void fix_length_and_dec() { + ulonglong max_result_length= (ulonglong) args[0]->max_length * 2 + 2; + max_length= min(max_result_length, MAX_BLOB_WIDTH); collation.set(args[0]->collation); - max_length= args[0]->max_length * 2 + 2; } }; -- cgit v1.2.1 From f57839cd6060ff2d8edb4bf0875b67d0176d88e4 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 26 Mar 2010 11:44:24 +0400 Subject: Bug#52177 crash with explain, row comparison, join, text field The crash is the result of an attempt made by JOIN::optimize to evaluate the WHERE condition when no records have been actually read. The fix is to remove erroneous 'outer_join' variable check. mysql-test/r/join.result: test result mysql-test/t/join.test: test case sql/sql_select.cc: removed erroneous 'outer_join' variable check. --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index cbc608ea972..84de1fe241b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1029,7 +1029,7 @@ JOIN::optimize() } } - if (conds &&!outer_join && const_table_map != found_const_table_map && + if (conds && const_table_map != found_const_table_map && (select_options & SELECT_DESCRIBE) && select_lex->master_unit() == &thd->lex->unit) // upper level SELECT { -- cgit v1.2.1 From 4775601012f81655643667d8635e46de120be7ae Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 28 Mar 2010 16:37:47 +0800 Subject: Bug #50095 Multi statement including CREATE EVENT causes rotten binlog entry The log event of 'CREATE EVENT' was being binlogged with garbage at the end of the query if 'CREATE EVENT' is followed by another SQL statement and they were executed as one command. for example: DELIMITER |; CREATE EVENT e1 ON EVERY DAY DO SELECT 1; SELECT 'a'; DELIMITER ;| When binlogging 'CREATE EVENT', we always create a new statement with definer and write it into the log event. The new statement is made from cpp_buf(preprocessed buffer). which is not a c string(end with '\0'), but it is copied as a c string. In this patch, cpp_buf is copied with its length. --- sql/events.cc | 4 +++- sql/sql_lex.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/events.cc b/sql/events.cc index 4c6dd0f35d1..afae512c61d 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -362,7 +362,9 @@ create_query_string(THD *thd, String *buf) /* Append definer */ append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host)); /* Append the left part of thd->query after "DEFINER" part */ - if (buf->append(thd->lex->stmt_definition_begin)) + if (buf->append(thd->lex->stmt_definition_begin, + thd->lex->stmt_definition_end - + thd->lex->stmt_definition_begin)) return 1; return 0; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 459878c03fc..54eefa22a59 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1729,6 +1729,7 @@ typedef struct st_lex : public Query_tables_list - CREATE TRIGGER (points to "TRIGGER"); - CREATE PROCEDURE (points to "PROCEDURE"); - CREATE FUNCTION (points to "FUNCTION" or "AGGREGATE"); + - CREATE EVENT (points to "EVENT") This pointer is required to add possibly omitted DEFINER-clause to the DDL-statement before dumping it to the binlog. -- cgit v1.2.1 From 454c003a5c5a31a8d59ba4ab54d3b3a90a609752 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 28 Mar 2010 19:57:33 +0800 Subject: Bug #50407 mysqlbinlog --database=X produces bad output for SAVEPOINTs When mysqlbinlog was given the --database=X flag, it always printed 'ROLLBACK TO', but the corresponding 'SAVEPOINT' statement was not printed. The replicated filter(replicated-do/ignore-db) and binlog filter (binlog-do/ignore-db) has the same problem. They are solved in this patch together. After this patch, We always check whether the query is 'SAVEPOINT' statement or not. Because this is a literal check, 'SAVEPOINT' and 'ROLLBACK TO' statements are also binlogged in uppercase with no any comments. The binlog before this patch can be handled correctly except one case that any comments are in front of the keywords. for example: /* bla bla */ SAVEPOINT a; /* bla bla */ ROLLBACK TO a; --- sql/log.cc | 26 +++++++++++++++++--------- sql/log_event.cc | 5 +---- sql/log_event.h | 22 ++++++++++++++++++++++ 3 files changed, 40 insertions(+), 13 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 6dfb8128ce9..e7090a98fd9 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1714,11 +1714,14 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) binlog_trans_log_savepos(thd, (my_off_t*) sv); /* Write it to the binary log */ + String log_query; + if (log_query.append(STRING_WITH_LEN("SAVEPOINT ")) || + log_query.append(thd->lex->ident.str, thd->lex->ident.length)) + DBUG_RETURN(1); 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); - DBUG_RETURN(error); + Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(), + TRUE, TRUE, errcode); + DBUG_RETURN(mysql_bin_log.write(&qinfo)); } static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) @@ -1733,11 +1736,14 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) if (unlikely(thd->transaction.all.modified_non_trans_table || (thd->options & OPTION_KEEP_LOG))) { + String log_query; + if (log_query.append(STRING_WITH_LEN("ROLLBACK TO ")) || + log_query.append(thd->lex->ident.str, thd->lex->ident.length)) + DBUG_RETURN(1); 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); - DBUG_RETURN(error); + Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(), + TRUE, TRUE, errcode); + DBUG_RETURN(mysql_bin_log.write(&qinfo)); } binlog_trans_log_truncate(thd, *(my_off_t*)sv); DBUG_RETURN(0); @@ -4272,7 +4278,9 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) */ const char *local_db= event_info->get_db(); if ((thd && !(thd->options & OPTION_BIN_LOG)) || - (!binlog_filter->db_ok(local_db))) + (thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT && + thd->lex->sql_command != SQLCOM_SAVEPOINT && + !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 e560580a909..a8e227fa99b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3063,10 +3063,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, ::do_apply_event(), then the companion SET also have so we don't need to reset_one_shot_variables(). */ - if (!strncmp(query_arg, "BEGIN", q_len_arg) || - !strncmp(query_arg, "COMMIT", q_len_arg) || - !strncmp(query_arg, "ROLLBACK", q_len_arg) || - rpl_filter->db_ok(thd->db)) + if (is_trans_keyword() || rpl_filter->db_ok(thd->db)) { thd->set_time((time_t)when); thd->set_query((char*)query_arg, q_len_arg); diff --git a/sql/log_event.h b/sql/log_event.h index 30a68955fb3..9b7f000648d 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1682,6 +1682,28 @@ public: /* !!! Public in this patch to allow old usage */ const char *query_arg, uint32 q_len_arg); #endif /* HAVE_REPLICATION */ + /* + If true, the event always be applied by slave SQL thread or be printed by + mysqlbinlog + */ + bool is_trans_keyword() + { + /* + Before the patch for bug#50407, The 'SAVEPOINT and ROLLBACK TO' + queries input by user was written into log events directly. + So the keywords can be written in both upper case and lower case + together, strncasecmp is used to check both cases. they also could be + binlogged with comments in the front of these keywords. for examples: + / * bla bla * / SAVEPOINT a; + / * bla bla * / ROLLBACK TO a; + but we don't handle these cases and after the patch, both quiries are + binlogged in upper case with no comments. + */ + return !strncmp(query, "BEGIN", q_len) || + !strncmp(query, "COMMIT", q_len) || + !strncasecmp(query, "SAVEPOINT", 9) || + !strncasecmp(query, "ROLLBACK", 8); + } }; -- cgit v1.2.1 From 28e95ba535e175dc696fe7a739736ae9bf2a2b36 Mon Sep 17 00:00:00 2001 From: "Tatiana A. Nurnberg" Date: Mon, 29 Mar 2010 03:32:30 +0100 Subject: Bug#48525: trigger changes "Column 'id' cannot be null" behaviour CHECK_FIELD_IGNORE was treated as CHECK_FIELD_ERROR_FOR_NULL; UPDATE...SET...NULL on NOT NULL fields behaved differently after a trigger. Now distinguishes between IGNORE and ERROR_FOR_NULL and save/restores check-field options. mysql-test/r/trigger.result: Show that UPDATE...SET...NULL on NOT NULL columns doesn't behave differently when run after a trigger. mysql-test/t/trigger.test: Show that UPDATE...SET...NULL on NOT NULL columns doesn't behave differently when run after a trigger. sql/field_conv.cc: CHECK_FIELD_IGNORE was treated as CHECK_FIELD_ERROR_FOR_NULL. Distinguish between the two. sql/sp_head.cc: Raise error as needed. sql/sql_class.cc: Save and restore check-fields options. sql/sql_class.h: Make room so we can save check-fields options. sql/sql_insert.cc: Raise error as needed. --- sql/field_conv.cc | 26 ++++++++++++++++++-------- sql/sp_head.cc | 1 + sql/sql_class.cc | 4 ++++ sql/sql_class.h | 1 + sql/sql_insert.cc | 2 +- 5 files changed, 25 insertions(+), 9 deletions(-) (limited to 'sql') diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 3574534722e..0bffde9671a 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -122,13 +122,18 @@ set_field_to_null(Field *field) return 0; } field->reset(); - if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN) - { + switch (field->table->in_use->count_cuted_fields) { + case CHECK_FIELD_WARN: field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + /* fall through */ + case CHECK_FIELD_IGNORE: return 0; + case CHECK_FIELD_ERROR_FOR_NULL: + if (!field->table->in_use->no_errors) + my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + return -1; } - if (!field->table->in_use->no_errors) - my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + DBUG_ASSERT(0); // impossible return -1; } @@ -178,13 +183,18 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions) field->table->auto_increment_field_not_null= FALSE; return 0; // field is set in fill_record() } - if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN) - { + switch (field->table->in_use->count_cuted_fields) { + case CHECK_FIELD_WARN: field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_BAD_NULL_ERROR, 1); + /* fall through */ + case CHECK_FIELD_IGNORE: return 0; + case CHECK_FIELD_ERROR_FOR_NULL: + if (!field->table->in_use->no_errors) + my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + return -1; } - if (!field->table->in_use->no_errors) - my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + DBUG_ASSERT(0); // impossible return -1; } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8a626cabd90..11d5e5f830b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3009,6 +3009,7 @@ int sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) { DBUG_ENTER("sp_instr_set_trigger_field::execute"); + thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 673fc9b78e6..266064f9f08 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3100,6 +3100,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, } #endif + backup->count_cuted_fields= count_cuted_fields; backup->options= options; backup->in_sub_stmt= in_sub_stmt; backup->enable_slow_log= enable_slow_log; @@ -3137,6 +3138,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, void THD::restore_sub_statement_state(Sub_statement_state *backup) { + DBUG_ENTER("THD::restore_sub_statement_state"); #ifndef EMBEDDED_LIBRARY /* BUG#33029, if we are replicating from a buggy master, restore auto_inc_intervals_forced so that the top statement can use the @@ -3163,6 +3165,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) /* ha_release_savepoint() never returns error. */ (void)ha_release_savepoint(this, sv); } + count_cuted_fields= backup->count_cuted_fields; transaction.savepoints= backup->savepoints; options= backup->options; in_sub_stmt= backup->in_sub_stmt; @@ -3192,6 +3195,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) */ examined_row_count+= backup->examined_row_count; cuted_fields+= backup->cuted_fields; + DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 032985dc44e..2ddd9358382 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -995,6 +995,7 @@ public: bool enable_slow_log; bool last_insert_id_used; SAVEPOINT *savepoints; + enum enum_check_fields count_cuted_fields; }; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 1f4ca90157f..35c24e7571e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3158,7 +3158,7 @@ bool select_insert::send_data(List &values) thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields store_values(values); - thd->count_cuted_fields= CHECK_FIELD_IGNORE; + thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; if (thd->is_error()) { table->auto_increment_field_not_null= FALSE; -- cgit v1.2.1 From 6eca53f1d382a247456d29794c70338f972b77a9 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Mon, 29 Mar 2010 18:42:49 +0500 Subject: fixed compiler warning --- sql/item_strfunc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index aedc63164f2..ab2bf006032 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -695,7 +695,7 @@ public: void fix_length_and_dec() { ulonglong max_result_length= (ulonglong) args[0]->max_length * 2 + 2; - max_length= min(max_result_length, MAX_BLOB_WIDTH); + max_length= (uint32) min(max_result_length, MAX_BLOB_WIDTH); collation.set(args[0]->collation); } }; -- cgit v1.2.1 From 55852670ccc6f8173fef7b26b544213ac0829dc0 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Wed, 31 Mar 2010 17:00:56 +0400 Subject: Fix for bug#52397: another crash with explain extended and group_concat Problem: EXPLAIN EXTENDED was trying to resolve references to freed temporary table fields for GROUP_CONCAT()'s ORDER BY arguments. Fix: use stored original GROUP_CONCAT()'s arguments in such a case. mysql-test/r/func_gconcat.result: Fix for bug#52397: another crash with explain extended and group_concat - test result. mysql-test/t/func_gconcat.test: Fix for bug#52397: another crash with explain extended and group_concat - test case. sql/item_sum.cc: Fix for bug#52397: another crash with explain extended and group_concat - use "pargs", printing ORDER BY arguments in the Item_func_group_concat::print() instead of "order" to avoid possible reference resolving to (freed) temporary table fields. --- sql/item_sum.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_sum.cc b/sql/item_sum.cc index c36fb8b8d64..8c1e5501a1b 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3420,7 +3420,7 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type) { if (i) str->append(','); - (*order[i]->item)->print(str, query_type); + pargs[i + arg_count_field]->print(str, query_type); if (order[i]->asc) str->append(STRING_WITH_LEN(" ASC")); else -- cgit v1.2.1 From e65caec1387ecc3b25a3a97c5ccedb9c16caa0ef Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 31 Mar 2010 16:12:37 +0300 Subject: Bug #37168: Missing variable - skip_name_resolve Added a read-only global boolean variable skip_name_resolve. --- sql/mysql_priv.h | 1 + sql/mysqld.cc | 3 +++ sql/set_var.cc | 4 ++++ 3 files changed, 8 insertions(+) (limited to 'sql') diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 098ea514cb6..56175d069c5 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1990,6 +1990,7 @@ extern my_bool opt_log, opt_slow_log; extern ulong log_output_options; extern my_bool opt_log_queries_not_using_indexes; extern bool opt_disable_networking, opt_skip_show_db; +extern bool opt_skip_name_resolve; extern bool opt_ignore_builtin_innodb; extern my_bool opt_character_set_client_handshake; extern bool volatile abort_loop, shutdown_in_progress; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index bb685ba42e3..716a5ff0305 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -410,6 +410,7 @@ ulong log_output_options; my_bool opt_log_queries_not_using_indexes= 0; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; +bool opt_skip_name_resolve=0; my_bool opt_character_set_client_handshake= 1; bool server_id_supplied = 0; bool opt_endinfo, using_udf_functions; @@ -7715,6 +7716,7 @@ static int mysql_init_variables(void) log_output_options= find_bit_type(log_output_str, &log_output_typelib); opt_bin_log= 0; opt_disable_networking= opt_skip_show_db=0; + opt_skip_name_resolve= 0; opt_ignore_builtin_innodb= 0; opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0; opt_tc_log_file= (char *)"tc.log"; // no hostname in tc_log file name ! @@ -8241,6 +8243,7 @@ mysqld_get_one_option(int optid, opt_specialflag|= SPECIAL_NO_HOST_CACHE; break; case (int) OPT_SKIP_RESOLVE: + opt_skip_name_resolve= 1; opt_specialflag|=SPECIAL_NO_RESOLVE; break; case (int) OPT_SKIP_NETWORKING: diff --git a/sql/set_var.cc b/sql/set_var.cc index 0a9541b9f2c..f7d9d9df42e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -533,6 +533,10 @@ static sys_var_const sys_skip_show_database(&vars, "skip_show_database", OPT_GLOBAL, SHOW_BOOL, (uchar*) &opt_skip_show_db); +static sys_var_const sys_skip_name_resolve(&vars, "skip_name_resolve", + OPT_GLOBAL, SHOW_BOOL, + (uchar*) &opt_skip_name_resolve); + static sys_var_const sys_socket(&vars, "socket", OPT_GLOBAL, SHOW_CHAR_PTR, (uchar*) &mysqld_unix_port); -- cgit v1.2.1 From ab8ff15cd148a0a5855d2474db78c05ec28f20c7 Mon Sep 17 00:00:00 2001 From: Anurag Shekhar Date: Fri, 2 Apr 2010 01:35:36 +0530 Subject: Bug #47904 Incorrect results w/ table subquery, derived SQs, and LEFT JOIN on index 'my_decimal' class has two members which can be used to access the value. The member variable buf (inherited from parent class decimal_t) is set to member variable buffer so that both are pointing to same value. Item_copy_decimal::copy() uses memcpy to clone 'my_decimal'. The member buffer is declared as an array and memcpy results in copying the values of the array, but the inherited member buf, which should be pointing at the begining of the array 'buffer' starts pointing to the begining of buffer in original object (which is being cloned). Further updates on 'my_decimal' updates only the inherited member 'buf' but leaves buffer unchanged. Later when the new object (which now holds a inconsistent value) is cloned again using proper cloning function 'my_decimal2decimal' the buf pointer is fixed resulting in loss of the current value. Using my_decimal2decimal instead of memcpy in Item_copy_decimal::copy() fixed this problem. mysql-test/r/subselect.result: Updated result file after addding test case for bug#47904. mysql-test/t/subselect.test: Added test case for bug#47904. sql/item.cc: Memcopy shouldn't be used to clone my_decimal. Use my_decimal2decimal instead. --- sql/item.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 809377e80b3..10da20beebe 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3515,7 +3515,7 @@ void Item_copy_decimal::copy() { my_decimal *nr= item->val_decimal(&cached_value); if (nr && nr != &cached_value) - memcpy (&cached_value, nr, sizeof (my_decimal)); + my_decimal2decimal (nr, &cached_value); null_value= item->null_value; } -- cgit v1.2.1 From e2a546aef46834b8250b3129ee87e944b4dd6ccb Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Sat, 3 Apr 2010 00:30:22 +0400 Subject: Bug #40625: Concat fails on DOUBLE values in a Stored Procedure, while DECIMAL works Selecting of the CONCAT(......) result into a user variable may return wrong data. Item_func_concat::val_str contains a number of memory allocation-saving tricks. One of them concatenates strings inplace inserting the value of one string at the beginning of the other string. However, this trick didn't care about strings those points to the same data buffer: this is possible when a CONCAT() parameter is a stored procedure variable - Item_sp_variable::val_str() uses the intermediate Item_sp_variable::str_value field, where it may store a reference to an external buffer. The Item_func_concat::val_str function has been modified to take into account val_str functions (such as Item_sp_variable::val_str) that return a pointer to an internal Item member variable that may reference to a buffer provided. mysql-test/r/func_concat.result: Test case for the bug #40625. mysql-test/t/func_concat.test: Test case for the bug #40625. sql/item_strfunc.cc: Bug #40625: Concat fails on DOUBLE values in a Stored Procedure, while DECIMAL works The Item_func_concat::val_str function has been modified to take into account val_str functions (such as Item_sp_variable::val_str) that return a pointer to an internal Item member variable that may reference to a buffer provided. --- sql/item_strfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 66308215d0b..b53172d631a 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -324,7 +324,7 @@ String *Item_func_concat::val_str(String *str) } else if (str->alloced_length() >= res->length()+res2->length()) { - if (str == res2) + if (str->ptr() == res2->ptr()) str->replace(0,0,*res); else { -- cgit v1.2.1 From c1ad5072b842c25732c278f0f7b60bccf8a23a94 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Mon, 5 Apr 2010 16:10:26 +0500 Subject: Bug#52336 Segfault / crash in 5.1 copy_fields (param=0x9872980) at sql_select.cc:15355 The problem is that we can not use make_cond_for_table(). This function relies on used_tables() condition which is not set properly for subqueries. As result subquery is not filtered out. The fix is to use remove_eq_conds() function instead of make_cond_for_table() func. 'remove_eq_conds()' algorithm relies on const_item() value and it allows to handle subqueries in right way. mysql-test/r/having.result: test case mysql-test/t/having.test: test case sql/sql_select.cc: The fix is to use remove_eq_conds() function instead of make_cond_for_table() function. --- sql/sql_select.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 545f1cb6636..a426f4b68a1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1125,13 +1125,13 @@ JOIN::optimize() elements may be lost during further having condition transformation in JOIN::exec. */ - if (having && !having->with_sum_func) + if (having && const_table_map) { - COND *const_cond= make_cond_for_table(having, const_table_map, 0); - DBUG_EXECUTE("where", print_where(const_cond, "const_having_cond", - QT_ORDINARY);); - if (const_cond && !const_cond->val_int()) + having->update_used_tables(); + having= remove_eq_conds(thd, having, &having_value); + if (having_value == Item::COND_FALSE) { + having= new Item_int((longlong) 0,1); zero_result_cause= "Impossible HAVING noticed after reading const tables"; DBUG_RETURN(0); } -- cgit v1.2.1