diff options
author | Sergei Golubchik <serg@mariadb.org> | 2014-05-25 10:18:07 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2014-05-25 10:18:07 +0200 |
commit | c2b9d993e33ac5099dfbde775af95e1400f40e87 (patch) | |
tree | 36fce8869bf6a02a33db9c0f630eb401de77b101 /sql | |
parent | a85186d7ab1b46bea7379e1e45fedeb193cfbcc4 (diff) | |
parent | 1016ee9d77e8c9cd6e9bd114b808fff66f398255 (diff) | |
download | mariadb-git-c2b9d993e33ac5099dfbde775af95e1400f40e87.tar.gz |
Merge branch '10.1' of bzr::/usr/home/serg/Abk/mysql into 10.1
Diffstat (limited to 'sql')
73 files changed, 742 insertions, 474 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 9efd33888bd..21b4236163b 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -279,7 +279,7 @@ ADD_CUSTOM_TARGET(distclean IF(INSTALL_LAYOUT STREQUAL "STANDALONE") # Copy db.opt into data/test/ -SET(DBOPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/db.opt ) +SET(DBOPT_FILE ${CMAKE_SOURCE_DIR}/support-files/db.opt ) INSTALL(FILES ${DBOPT_FILE} DESTINATION data/test COMPONENT DataFiles) # Install initial database on windows diff --git a/sql/db.opt b/sql/db.opt deleted file mode 100644 index d8429c4e0de..00000000000 --- a/sql/db.opt +++ /dev/null @@ -1,2 +0,0 @@ -default-character-set=latin1 -default-collation=latin1_swedish_ci diff --git a/sql/filesort.cc b/sql/filesort.cc index 776ec064365..0d554df6e18 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 2009, 2012, Monty Program Ab. +/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. + Copyright (c) 2009, 2014, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index e683fb91700..f503b2f54e5 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -8145,7 +8145,6 @@ class ha_partition_inplace_ctx : public inplace_alter_handler_ctx { public: inplace_alter_handler_ctx **handler_ctx_array; - bool rollback_done; private: uint m_tot_parts; @@ -8153,7 +8152,6 @@ public: ha_partition_inplace_ctx(THD *thd, uint tot_parts) : inplace_alter_handler_ctx(), handler_ctx_array(NULL), - rollback_done(false), m_tot_parts(tot_parts) {} @@ -8172,14 +8170,11 @@ enum_alter_inplace_result ha_partition::check_if_supported_inplace_alter(TABLE *altered_table, Alter_inplace_info *ha_alter_info) { -#ifdef PARTITION_SUPPORTS_INPLACE_ALTER uint index= 0; enum_alter_inplace_result result= HA_ALTER_INPLACE_NO_LOCK; ha_partition_inplace_ctx *part_inplace_ctx; + bool first_is_set= false; THD *thd= ha_thd(); -#else - enum_alter_inplace_result result= HA_ALTER_INPLACE_NOT_SUPPORTED; -#endif DBUG_ENTER("ha_partition::check_if_supported_inplace_alter"); /* @@ -8190,34 +8185,21 @@ ha_partition::check_if_supported_inplace_alter(TABLE *altered_table, if (ha_alter_info->alter_info->flags == Alter_info::ALTER_PARTITION) DBUG_RETURN(HA_ALTER_INPLACE_NO_LOCK); -#ifndef PARTITION_SUPPORTS_INPLACE_ALTER - /* - Due to bug#14760210 partitions can be out-of-sync in case - commit_inplace_alter_table fails after the first partition. - - Until we can either commit all partitions at the same time or - have an atomic recover on failure/crash we don't support any - inplace alter. - - TODO: investigate what happens when indexes are out-of-sync - between partitions. If safe and possible to recover from, - then we could allow ADD/DROP INDEX. - */ - DBUG_RETURN(result); -#else part_inplace_ctx= new (thd->mem_root) ha_partition_inplace_ctx(thd, m_tot_parts); if (!part_inplace_ctx) DBUG_RETURN(HA_ALTER_ERROR); part_inplace_ctx->handler_ctx_array= (inplace_alter_handler_ctx **) - thd->alloc(sizeof(inplace_alter_handler_ctx *) * m_tot_parts); + thd->alloc(sizeof(inplace_alter_handler_ctx *) * (m_tot_parts + 1)); if (!part_inplace_ctx->handler_ctx_array) DBUG_RETURN(HA_ALTER_ERROR); - for (index= 0; index < m_tot_parts; index++) + /* Set all to NULL, including the terminating one. */ + for (index= 0; index <= m_tot_parts; index++) part_inplace_ctx->handler_ctx_array[index]= NULL; + ha_alter_info->handler_flags |= Alter_inplace_info::ALTER_PARTITIONED; for (index= 0; index < m_tot_parts; index++) { enum_alter_inplace_result p_result= @@ -8225,15 +8207,32 @@ ha_partition::check_if_supported_inplace_alter(TABLE *altered_table, ha_alter_info); part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx; + if (index == 0) + { + first_is_set= (ha_alter_info->handler_ctx != NULL); + } + else if (first_is_set != (ha_alter_info->handler_ctx != NULL)) + { + /* Either none or all partitions must set handler_ctx! */ + DBUG_ASSERT(0); + DBUG_RETURN(HA_ALTER_ERROR); + } if (p_result < result) result= p_result; if (result == HA_ALTER_ERROR) break; } + ha_alter_info->handler_ctx= part_inplace_ctx; + /* + To indicate for future inplace calls that there are several + partitions/handlers that need to be committed together, + we set group_commit_ctx to the NULL terminated array of + the partitions handlers. + */ + ha_alter_info->group_commit_ctx= part_inplace_ctx->handler_ctx_array; DBUG_RETURN(result); -#endif } @@ -8314,8 +8313,8 @@ bool ha_partition::commit_inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info, bool commit) { - uint index= 0; ha_partition_inplace_ctx *part_inplace_ctx; + bool error= false; DBUG_ENTER("ha_partition::commit_inplace_alter_table"); @@ -8329,117 +8328,52 @@ bool ha_partition::commit_inplace_alter_table(TABLE *altered_table, part_inplace_ctx= static_cast<class ha_partition_inplace_ctx*>(ha_alter_info->handler_ctx); - if (!commit && part_inplace_ctx->rollback_done) - DBUG_RETURN(false); // We have already rolled back changes. - - for (index= 0; index < m_tot_parts; index++) + if (commit) { - ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[index]; - if (m_file[index]->ha_commit_inplace_alter_table(altered_table, - ha_alter_info, commit)) + DBUG_ASSERT(ha_alter_info->group_commit_ctx == + part_inplace_ctx->handler_ctx_array); + ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[0]; + error= m_file[0]->ha_commit_inplace_alter_table(altered_table, + ha_alter_info, commit); + if (error) + goto end; + if (ha_alter_info->group_commit_ctx) { - part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx; - goto err; - } - part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx; - DBUG_EXECUTE_IF("ha_partition_fail_final_add_index", { - /* Simulate failure by rollback of the second partition */ - if (m_tot_parts > 1) + /* + If ha_alter_info->group_commit_ctx is not set to NULL, + then the engine did only commit the first partition! + The engine is probably new, since both innodb and the default + implementation of handler::commit_inplace_alter_table sets it to NULL + and simply return false, since it allows metadata changes only. + Loop over all other partitions as to follow the protocol! + */ + uint i; + DBUG_ASSERT(0); + for (i= 1; i < m_tot_parts; i++) { - index++; - ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[index]; - m_file[index]->ha_commit_inplace_alter_table(altered_table, - ha_alter_info, false); - part_inplace_ctx->handler_ctx_array[index]= ha_alter_info->handler_ctx; - goto err; + ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[i]; + error|= m_file[i]->ha_commit_inplace_alter_table(altered_table, + ha_alter_info, + true); } - }); } - ha_alter_info->handler_ctx= part_inplace_ctx; - - DBUG_RETURN(false); - -err: - ha_alter_info->handler_ctx= part_inplace_ctx; - /* - Reverting committed changes is (for now) only possible for ADD INDEX - For other changes we will just try to rollback changes. - */ - if (index > 0 && - ha_alter_info->handler_flags & (Alter_inplace_info::ADD_INDEX | - Alter_inplace_info::ADD_UNIQUE_INDEX | - Alter_inplace_info::ADD_PK_INDEX)) - { - Alter_inplace_info drop_info(ha_alter_info->create_info, - ha_alter_info->alter_info, - NULL, 0, - ha_alter_info->modified_part_info, - ha_alter_info->ignore); - - if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_INDEX) - drop_info.handler_flags|= Alter_inplace_info::DROP_INDEX; - if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_UNIQUE_INDEX) - drop_info.handler_flags|= Alter_inplace_info::DROP_UNIQUE_INDEX; - if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_PK_INDEX) - drop_info.handler_flags|= Alter_inplace_info::DROP_PK_INDEX; - drop_info.index_drop_count= ha_alter_info->index_add_count; - drop_info.index_drop_buffer= - (KEY**) ha_thd()->alloc(sizeof(KEY*) * drop_info.index_drop_count); - if (!drop_info.index_drop_buffer) - { - sql_print_error("Failed with error handling of adding index:\n" - "committing index failed, and when trying to revert " - "already committed partitions we failed allocating\n" - "memory for the index for table '%s'", - table_share->table_name.str); - DBUG_RETURN(true); - } - for (uint i= 0; i < drop_info.index_drop_count; i++) - drop_info.index_drop_buffer[i]= - &ha_alter_info->key_info_buffer[ha_alter_info->index_add_buffer[i]]; - - // Drop index for each partition where we already committed new index. - for (uint i= 0; i < index; i++) - { - bool error= m_file[i]->ha_prepare_inplace_alter_table(altered_table, - &drop_info); - error|= m_file[i]->ha_inplace_alter_table(altered_table, &drop_info); - error|= m_file[i]->ha_commit_inplace_alter_table(altered_table, - &drop_info, true); - if (error) - sql_print_error("Failed with error handling of adding index:\n" - "committing index failed, and when trying to revert " - "already committed partitions we failed removing\n" - "the index for table '%s' partition nr %d", - table_share->table_name.str, i); } - - // Rollback uncommitted changes. - for (uint i= index+1; i < m_tot_parts; i++) + else + { + uint i; + for (i= 0; i < m_tot_parts; i++) { + /* Rollback, commit == false, is done for each partition! */ ha_alter_info->handler_ctx= part_inplace_ctx->handler_ctx_array[i]; if (m_file[i]->ha_commit_inplace_alter_table(altered_table, ha_alter_info, false)) - { - /* How could this happen? */ - sql_print_error("Failed with error handling of adding index:\n" - "Rollback of add_index failed for table\n" - "'%s' partition nr %d", - table_share->table_name.str, i); + error= true; } - part_inplace_ctx->handler_ctx_array[i]= ha_alter_info->handler_ctx; } - - // We have now reverted/rolled back changes. Set flag to prevent - // it from being done again. - part_inplace_ctx->rollback_done= true; - - print_error(HA_ERR_NO_PARTITION_FOUND, MYF(0)); - } - +end: ha_alter_info->handler_ctx= part_inplace_ctx; - DBUG_RETURN(true); + DBUG_RETURN(error); } diff --git a/sql/handler.cc b/sql/handler.cc index 3cb2106a443..ac2512431ad 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -359,6 +359,7 @@ int ha_init_errors(void) SETMSG(HA_FTS_INVALID_DOCID, "Invalid InnoDB FTS Doc ID"); SETMSG(HA_ERR_TABLE_IN_FK_CHECK, ER_DEFAULT(ER_TABLE_IN_FK_CHECK)); SETMSG(HA_ERR_DISK_FULL, ER_DEFAULT(ER_DISK_FULL)); + SETMSG(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE, "Too many words in a FTS phrase or proximity search"); /* Register the error messages for use with my_error(). */ return my_error_register(get_handler_errmsgs, HA_ERR_FIRST, HA_ERR_LAST); @@ -3888,14 +3889,11 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) if it is started. */ +inline void -handler::mark_trx_read_write_part2() +handler::mark_trx_read_write() { Ha_trx_info *ha_info= &ha_thd()->ha_data[ht->slot].ha_info[0]; - - /* Don't call this function again for this statement */ - mark_trx_done= TRUE; - /* When a storage engine method is called, the transaction must have been started, unless it's a DDL call, for which the @@ -6114,6 +6112,10 @@ void signal_log_not_needed(struct handlerton, char *log_file) DBUG_VOID_RETURN; } +void handler::set_lock_type(enum thr_lock_type lock) +{ + table->reginfo.lock_type= lock; +} #ifdef TRANS_LOG_MGM_EXAMPLE_CODE /* diff --git a/sql/handler.h b/sql/handler.h index 0b8bd6e9ce6..5bba570f8ec 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1,8 +1,8 @@ #ifndef HANDLER_INCLUDED #define HANDLER_INCLUDED /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. - Copyright (c) 2009, 2013, Monty Program Ab. + Copyright (c) 2000, 2014, Oracle and/or its affiliates. + Copyright (c) 2009, 2014, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -1610,7 +1610,7 @@ struct HA_CREATE_INFO For ALTER TABLE defaults to ROW_TYPE_NOT_USED (means "keep the current"). Can be changed either explicitly by the parser. - If nothing speficied inherits the value of the original table (if present). + If nothing specified inherits the value of the original table (if present). */ enum row_type row_type; enum ha_choice transactional; @@ -1677,8 +1677,7 @@ public: All these operations are supported as in-place operations by the SQL layer. This means that operations that by their nature must be performed by copying the table to a temporary table, will not - have their own flags here (e.g. ALTER TABLE FORCE, ALTER TABLE - ENGINE). + have their own flags here. We generally try to specify handler flags only if there are real changes. But in cases when it is cumbersome to determine if some @@ -1782,8 +1781,17 @@ public: // Partition operation with ALL keyword static const HA_ALTER_FLAGS ALTER_ALL_PARTITION = 1L << 28; + /** + Recreate the table for ALTER TABLE FORCE, ALTER TABLE ENGINE + and OPTIMIZE TABLE operations. + */ + static const HA_ALTER_FLAGS RECREATE_TABLE = 1L << 29; + // Virtual columns changed - static const HA_ALTER_FLAGS ALTER_COLUMN_VCOL = 1L << 29; + static const HA_ALTER_FLAGS ALTER_COLUMN_VCOL = 1L << 30; + + // ALTER TABLE for a partitioned table + static const HA_ALTER_FLAGS ALTER_PARTITIONED = 1L << 31; /** Create options (like MAX_ROWS) for the new version of table. @@ -1856,6 +1864,18 @@ public: inplace_alter_handler_ctx *handler_ctx; /** + If the table uses several handlers, like ha_partition uses one handler + per partition, this contains a Null terminated array of ctx pointers + that should all be committed together. + Or NULL if only handler_ctx should be committed. + Set to NULL if the low level handler::commit_inplace_alter_table uses it, + to signal to the main handler that everything was committed as atomically. + + @see inplace_alter_handler_ctx for information about object lifecycle. + */ + inplace_alter_handler_ctx **group_commit_ctx; + + /** Flags describing in detail which operations the storage engine is to execute. */ HA_ALTER_FLAGS handler_flags; @@ -1903,6 +1923,7 @@ public: index_add_count(0), index_add_buffer(NULL), handler_ctx(NULL), + group_commit_ctx(NULL), handler_flags(0), modified_part_info(modified_part_info_arg), ignore(ignore_arg), @@ -2450,7 +2471,6 @@ public: FT_INFO *ft_handler; enum {NONE=0, INDEX, RND} inited; bool implicit_emptied; /* Can be !=0 only if HEAP */ - bool mark_trx_done; const COND *pushed_cond; /** next_insert_id is the next value which should be inserted into the @@ -2531,7 +2551,7 @@ public: in_range_check_pushed_down(FALSE), ref_length(sizeof(my_off_t)), ft_handler(0), inited(NONE), - implicit_emptied(0), mark_trx_done(FALSE), + implicit_emptied(0), pushed_cond(0), next_insert_id(0), insert_id_for_cur_row(0), pushed_idx_cond(NULL), pushed_idx_cond_keyno(MAX_KEY), @@ -2612,13 +2632,6 @@ public: } int ha_rnd_init_with_error(bool scan) __attribute__ ((warn_unused_result)); int ha_reset(); - /* Tell handler (not storage engine) this is start of a new statement */ - void ha_start_of_new_statement() - { - ft_handler= 0; - mark_trx_done= FALSE; - } - /* this is necessary in many places, e.g. in HANDLER command */ int ha_index_or_rnd_end() { @@ -3622,6 +3635,10 @@ protected: @note In case of partitioning, this function might be called for rollback without prepare_inplace_alter_table() having been called first. + Also partitioned tables sets ha_alter_info->group_commit_ctx to a NULL + terminated array of the partitions handlers and if all of them are + committed as one, then group_commit_ctx should be set to NULL to indicate + to the partitioning handler that all partitions handlers are committed. @see prepare_inplace_alter_table(). @param altered_table TABLE object for new version of table. @@ -3636,7 +3653,11 @@ protected: virtual bool commit_inplace_alter_table(TABLE *altered_table, Alter_inplace_info *ha_alter_info, bool commit) - { return false; } +{ + /* Nothing to commit/rollback, mark all handlers committed! */ + ha_alter_info->group_commit_ctx= NULL; + return false; +} /** @@ -3709,12 +3730,8 @@ protected: private: /* Private helpers */ - void mark_trx_read_write_part2(); - inline void mark_trx_read_write() - { - if (!mark_trx_done) - mark_trx_read_write_part2(); - } + inline void mark_trx_read_write(); +private: inline void increment_statistics(ulong SSV::*offset) const; inline void decrement_statistics(ulong SSV::*offset) const; @@ -3920,6 +3937,8 @@ public: inline int ha_write_tmp_row(uchar *buf); inline int ha_update_tmp_row(const uchar * old_data, uchar * new_data); + virtual void set_lock_type(enum thr_lock_type lock); + friend enum icp_result handler_index_cond_check(void* h_arg); protected: Handler_share *get_ha_share_ptr(); diff --git a/sql/hostname.cc b/sql/hostname.cc index 11cd16ac857..c6c58a0db92 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. Copyright (c) 2011, 2014, SkySQL Ab. This program is free software; you can redistribute it and/or modify @@ -457,12 +457,12 @@ int ip_to_hostname(struct sockaddr_storage *ip_storage, if (entry) { entry->m_last_seen= now; + *connect_errors= entry->m_errors.m_connect; - if (entry->m_errors.m_connect > max_connect_errors) + if (entry->m_errors.m_connect >= max_connect_errors) { entry->m_errors.m_host_blocked++; entry->set_error_timestamps(now); - *connect_errors= entry->m_errors.m_connect; mysql_mutex_unlock(&hostname_cache->lock); DBUG_RETURN(RC_BLOCKED_HOST); } diff --git a/sql/item.cc b/sql/item.cc index 58131e1eaea..2c963322eb6 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4742,6 +4742,10 @@ bool is_outer_table(TABLE_LIST *table, SELECT_LEX *select) DBUG_ASSERT(table->select_lex != select); TABLE_LIST *tl; + if (table->belong_to_view && + table->belong_to_view->select_lex == select) + return FALSE; + for (tl= select->master_unit()->derived; tl && tl->is_merged_derived(); select= tl->select_lex, tl= select->master_unit()->derived) @@ -5318,15 +5322,23 @@ mark_non_agg_field: /* Mark selects according to presence of non aggregated fields. Fields from outer selects added to the aggregate function - outer_fields list as its unknown at the moment whether it's + outer_fields list as it's unknown at the moment whether it's aggregated or not. - We're using either the select lex of the cached table (if present) - or the field's resolution context. context->select_lex is - safe for use because it's either the SELECT we want to use - (the current level) or a stub added by non-SELECT queries. + We're using the select lex of the cached table (if present). */ - SELECT_LEX *select_lex= cached_table ? - cached_table->select_lex : field->table->pos_in_table_list->select_lex; + SELECT_LEX *select_lex; + if (cached_table) + select_lex= cached_table->select_lex; + else if (!(select_lex= field->table->pos_in_table_list->select_lex)) + { + /* + This can only happen when there is no real table in the query. + We are using the field's resolution context. context->select_lex is eee + safe for use because it's either the SELECT we want to use + (the current level) or a stub added by non-SELECT queries. + */ + select_lex= context->select_lex; + } if (!thd->lex->in_sum_func) select_lex->set_non_agg_field_used(true); else diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 5028e18a6d7..f142c51db4d 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2763,13 +2763,13 @@ Item_func_nullif::fix_length_and_dec() maybe_null=1; if (args[0]) // Only false if EOM { - max_length=args[0]->max_length; decimals=args[0]->decimals; unsigned_flag= args[0]->unsigned_flag; cached_result_type= args[0]->result_type(); if (cached_result_type == STRING_RESULT && agg_arg_charsets_for_comparison(collation, args, arg_count)) return; + fix_char_length(args[0]->max_char_length()); } } diff --git a/sql/item_func.cc b/sql/item_func.cc index eb176d7e490..be5dcd070a1 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -6250,18 +6250,39 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref) bool allows_multi_table_search= true; const_item_cache=0; + table= 0; for (uint i=1 ; i < arg_count ; i++) { item=args[i]; if (item->type() == Item::REF_ITEM) args[i]= item= *((Item_ref *)item)->ref; - if (item->type() != Item::FIELD_ITEM) + /* + When running in PS mode, some Item_field's can already be replaced + to Item_func_conv_charset during PREPARE time. This is possible + in case of "MATCH (f1,..,fN) AGAINST (... IN BOOLEAN MODE)" + when running without any fulltext indexes and when fields f1..fN + have different character sets. + So we check for FIELD_ITEM only during prepare time and in non-PS mode, + and do not check in PS execute time. + */ + if (!thd->stmt_arena->is_stmt_execute() && + item->type() != Item::FIELD_ITEM) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "AGAINST"); return TRUE; } - allows_multi_table_search &= - allows_search_on_non_indexed_columns(((Item_field *)item)->field->table); + /* + During the prepare-time execution of fix_fields() of a PS query some + Item_fields's could have been already replaced to Item_func_conv_charset + (by the call for agg_arg_charsets_for_comparison below()). + But agg_arg_charsets_for_comparison() is written in a way that + at least *one* of the Item_field's is not replaced. + This makes sure that "table" gets initialized during PS execution time. + */ + if (item->type() == Item::FIELD_ITEM) + table= ((Item_field *)item)->field->table; + + allows_multi_table_search &= allows_search_on_non_indexed_columns(table); } /* @@ -6277,15 +6298,13 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref) my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH"); return TRUE; } - table=((Item_field *)item)->field->table; if (!(table->file->ha_table_flags() & HA_CAN_FULLTEXT)) { my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0), table->file->table_type()); return 1; } table->fulltext_searched=1; - return agg_item_collations_for_comparison(cmp_collation, func_name(), - args+1, arg_count-1, 0); + return agg_arg_charsets_for_comparison(cmp_collation, args+1, arg_count-1); } bool Item_func_match::fix_index() diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 1ae080ba22d..100d54133dd 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1604,7 +1604,7 @@ String *Item_str_conv::val_str(String *str) if (multiply == 1) { uint len; - res= copy_if_not_alloced(str,res,res->length()); + res= copy_if_not_alloced(&tmp_value, res, res->length()); len= converter(collation.collation, (char*) res->ptr(), res->length(), (char*) res->ptr(), res->length()); DBUG_ASSERT(len <= res->length()); @@ -1810,8 +1810,10 @@ void Item_func_substr_index::fix_length_and_dec() String *Item_func_substr_index::val_str(String *str) { DBUG_ASSERT(fixed == 1); + char buff[MAX_FIELD_WIDTH]; + String tmp(buff,sizeof(buff),system_charset_info); String *res= args[0]->val_str(str); - String *delimiter= args[1]->val_str(&tmp_value); + String *delimiter= args[1]->val_str(&tmp); int32 count= (int32) args[2]->val_int(); uint offset; @@ -1918,6 +1920,8 @@ String *Item_func_substr_index::val_str(String *str) break; } } + if (count) + return res; // Didn't find, return org string } } /* diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index f2f5b7b1b63..0aaeb3d55db 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2523,10 +2523,10 @@ bool Item_date_typecast::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) if (get_arg0_date(ltime, fuzzy_date & ~TIME_TIME_ONLY)) return 1; - ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; - ltime->time_type= MYSQL_TIMESTAMP_DATE; - return (null_value= check_date_with_warn(ltime, fuzzy_date, - MYSQL_TIMESTAMP_DATE)); + if (make_date_with_warn(ltime, fuzzy_date, MYSQL_TIMESTAMP_DATE)) + return (null_value= 1); + + return 0; } diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 30db7e635e2..759b929ff82 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -2899,7 +2899,7 @@ bool Item_func_xml_update::collect_result(String *str, str->length(0); str->set_charset(collation.collation); return - /* Put the XML part preceeding the replaced piece */ + /* Put the XML part preceding the replaced piece */ str->append(xml.raw()->ptr(), cut->beg - xml.raw()->ptr() - offs) || /* Put the replacement */ str->append(replace->ptr(), replace->length()) || diff --git a/sql/lock.cc b/sql/lock.cc index d5124ebc0f8..54c7720e750 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -323,6 +323,8 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags) (void) unlock_external(thd, sql_lock->table, sql_lock->table_count); end: + THD_STAGE_INFO(thd, stage_after_table_lock); + if (thd->killed) { thd->send_kill_message(); diff --git a/sql/log_event.cc b/sql/log_event.cc index 6610c436302..9846bade696 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1,6 +1,6 @@ /* - Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2013, Monty Program Ab. + Copyright (c) 2000, 2014, Oracle and/or its affiliates. + Copyright (c) 2009, 2014, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -41,6 +41,7 @@ #include "transaction.h" #include <my_dir.h> #include "sql_show.h" // append_identifier +#include <mysql/psi/mysql_statement.h> #include <strfunc.h> #include "compat56.h" @@ -4086,7 +4087,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, if ((error= rows_event_stmt_cleanup(rgi, thd))) { const_cast<Relay_log_info*>(rli)->report(ERROR_LEVEL, error, - "Error in cleaning up after an event preceeding the commit; " + "Error in cleaning up after an event preceding the commit; " "the group log file/position: %s %s", const_cast<Relay_log_info*>(rli)->group_master_log_name, llstr(const_cast<Relay_log_info*>(rli)->group_master_log_pos, @@ -4272,6 +4273,13 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, Parser_state parser_state; if (!parser_state.init(thd, thd->query(), thd->query_length())) { + thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state, + stmt_info_rpl.m_key, + thd->db, thd->db_length, + thd->charset()); + THD_STAGE_INFO(thd, stage_init); + MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), thd->query_length()); + mysql_parse(thd, thd->query(), thd->query_length(), &parser_state); /* Finalize server status flags after executing a statement. */ thd->update_server_status(); @@ -4455,6 +4463,11 @@ end: thd->set_db(NULL, 0); /* will free the current database */ thd->reset_query(); DBUG_PRINT("info", ("end: query= 0")); + + /* Mark the statement completed. */ + MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); + thd->m_statement_psi= NULL; + /* As a disk space optimization, future masters will not log an event for LAST_INSERT_ID() if that function returned 0 (and thus they will be able @@ -9432,8 +9445,31 @@ int Rows_log_event::do_add_row_data(uchar *row_data, size_t length) if (static_cast<size_t>(m_rows_end - m_rows_cur) <= length) { size_t const block_size= 1024; - my_ptrdiff_t const cur_size= m_rows_cur - m_rows_buf; - my_ptrdiff_t const new_alloc= + ulong cur_size= m_rows_cur - m_rows_buf; + DBUG_EXECUTE_IF("simulate_too_big_row_case1", + cur_size= UINT_MAX32 - (block_size * 10); + length= UINT_MAX32 - (block_size * 10);); + DBUG_EXECUTE_IF("simulate_too_big_row_case2", + cur_size= UINT_MAX32 - (block_size * 10); + length= block_size * 10;); + DBUG_EXECUTE_IF("simulate_too_big_row_case3", + cur_size= block_size * 10; + length= UINT_MAX32 - (block_size * 10);); + DBUG_EXECUTE_IF("simulate_too_big_row_case4", + cur_size= UINT_MAX32 - (block_size * 10); + length= (block_size * 10) - block_size + 1;); + ulong remaining_space= UINT_MAX32 - cur_size; + /* Check that the new data fits within remaining space and we can add + block_size without wrapping. + */ + if (length > remaining_space || + ((length + block_size) > remaining_space)) + { + sql_print_error("The row data is greater than 4GB, which is too big to " + "write to the binary log."); + DBUG_RETURN(ER_BINLOG_ROW_LOGGING_FAILED); + } + ulong const new_alloc= block_size * ((cur_size + length + block_size - 1) / block_size); uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, (uint) new_alloc, @@ -9753,10 +9789,14 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) /* Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc Don't allow generation of auto_increment value when processing - rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. + rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. The exception + to this rule happens when the auto_inc column exists on some + extra columns on the slave. In that case, do not force + MODE_NO_AUTO_VALUE_ON_ZERO. */ ulonglong saved_sql_mode= thd->variables.sql_mode; - thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO; + if (!is_auto_inc_in_extra_columns()) + thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO; // row processing loop @@ -11085,9 +11125,28 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability * table->auto_increment_field_not_null and SQL_MODE(if includes * MODE_NO_AUTO_VALUE_ON_ZERO) in update_auto_increment function. * SQL_MODE of slave sql thread is always consistency with master's. - * In RBR, auto_increment fields never are NULL. + * In RBR, auto_increment fields never are NULL, except if the auto_inc + * column exists only on the slave side (i.e., in an extra column + * on the slave's table). */ - m_table->auto_increment_field_not_null= TRUE; + if (!is_auto_inc_in_extra_columns()) + m_table->auto_increment_field_not_null= TRUE; + else + { + /* + Here we have checked that there is an extra field + on this server's table that has an auto_inc column. + + Mark that the auto_increment field is null and mark + the read and write set bits. + + (There can only be one AUTO_INC column, it is always + indexed and it cannot have a DEFAULT value). + */ + m_table->auto_increment_field_not_null= FALSE; + m_table->mark_auto_increment_column(); + } + return error; } @@ -11096,6 +11155,19 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability * int error) { int local_error= 0; + + /** + Clear the write_set bit for auto_inc field that only + existed on the destination table as an extra column. + */ + if (is_auto_inc_in_extra_columns()) + { + bitmap_clear_bit(m_table->write_set, m_table->next_number_field->field_index); + bitmap_clear_bit( m_table->read_set, m_table->next_number_field->field_index); + + if (get_flags(STMT_END_F)) + m_table->file->ha_release_auto_increment(); + } m_table->next_number_field=0; m_table->auto_increment_field_not_null= FALSE; if ((slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT) || @@ -11248,7 +11320,13 @@ Rows_log_event::write_row(rpl_group_info *rgi, ulong estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row); table->file->ha_start_bulk_insert(estimated_rows); } - + + /* + Explicitly set the auto_inc to null to make sure that + it gets an auto_generated value. + */ + if (is_auto_inc_in_extra_columns()) + m_table->next_number_field->set_null(); #ifndef DBUG_OFF DBUG_DUMP("record[0]", table->record[0], table->s->reclength); diff --git a/sql/log_event.h b/sql/log_event.h index 11cbfd191f2..2091d968558 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2013, Monty Program Ab. +/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. + Copyright (c) 2009, 2014, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2004,7 +2004,7 @@ public: bool is_valid() const { return query != 0; } /* - Returns number of bytes additionaly written to post header by derived + Returns number of bytes additionally written to post header by derived events (so far it is only Execute_load_query event). */ virtual ulong get_post_header_size_for_derived() { return 0; } @@ -4343,7 +4343,21 @@ protected: bool process_triggers(trg_event_type event, trg_action_time_type time_type, bool old_row_is_record1); -#endif //defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) + + /** + Helper function to check whether there is an auto increment + column on the table where the event is to be applied. + + @return true if there is an autoincrement field on the extra + columns, false otherwise. + */ + inline bool is_auto_inc_in_extra_columns() + { + DBUG_ASSERT(m_table); + return (m_table->next_number_field && + m_table->next_number_field->field_index >= m_width); + } +#endif private: diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 438c56659b0..90d6659cdcf 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. +/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. Copyright (c) 2008, 2014, SkySQL Ab. This program is free software; you can redistribute it and/or modify @@ -338,6 +338,13 @@ static PSI_rwlock_key key_rwlock_openssl; volatile sig_atomic_t ld_assume_kernel_is_set= 0; #endif +/** + Statement instrumentation key for replication. +*/ +#ifdef HAVE_PSI_STATEMENT_INTERFACE +PSI_statement_info stmt_info_rpl; +#endif + /* the default log output is log tables */ static bool lower_case_table_names_used= 0; static bool max_long_data_size_used= false; @@ -2230,7 +2237,7 @@ static struct passwd *check_user(const char *user) } if (!user) { - if (!opt_bootstrap) + if (!opt_bootstrap && !opt_help) { sql_print_error("Fatal error: Please read \"Security\" section of the manual to find out how to run mysqld as root!\n"); unireg_abort(1); @@ -3791,7 +3798,7 @@ void init_com_statement_info() com_statement_info[index].m_flags= 0; } - /* "statement/com/query" can mutate into "statement/sql/..." */ + /* "statement/abstract/query" can mutate into "statement/sql/..." */ com_statement_info[(uint) COM_QUERY].m_flags= PSI_FLAG_MUTABLE; } #endif @@ -7090,7 +7097,7 @@ struct my_option my_long_options[]= GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"plugin-load-add", OPT_PLUGIN_LOAD_ADD, "Optional semicolon-separated list of plugins to load. This option adds " - "to the list speficied by --plugin-load in an incremental way. " + "to the list specified by --plugin-load in an incremental way. " "It can be specified many times, adding more plugins every time.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -9335,6 +9342,8 @@ static PSI_file_info all_server_files[]= #endif /* HAVE_PSI_INTERFACE */ PSI_stage_info stage_after_create= { 0, "After create", 0}; +PSI_stage_info stage_after_opening_tables= { 0, "After opening tables", 0}; +PSI_stage_info stage_after_table_lock= { 0, "After table lock", 0}; PSI_stage_info stage_allocating_local_table= { 0, "allocating local table", 0}; PSI_stage_info stage_alter_inplace_prepare= { 0, "preparing for alter table", 0}; PSI_stage_info stage_alter_inplace= { 0, "altering table", 0}; @@ -9363,6 +9372,7 @@ PSI_stage_info stage_end= { 0, "end", 0}; PSI_stage_info stage_executing= { 0, "executing", 0}; PSI_stage_info stage_execution_of_init_command= { 0, "Execution of init_command", 0}; PSI_stage_info stage_explaining= { 0, "explaining", 0}; +PSI_stage_info stage_finding_key_cache= { 0, "Finding key cache", 0}; PSI_stage_info stage_finished_reading_one_binlog_switching_to_next_binlog= { 0, "Finished reading one binlog; switching to next binlog", 0}; PSI_stage_info stage_flushing_relay_log_and_master_info_repository= { 0, "Flushing relay log and master info repository.", 0}; PSI_stage_info stage_flushing_relay_log_info_file= { 0, "Flushing relay-log info file.", 0}; @@ -9387,6 +9397,7 @@ PSI_stage_info stage_purging_old_relay_logs= { 0, "Purging old relay logs", 0}; PSI_stage_info stage_query_end= { 0, "query end", 0}; PSI_stage_info stage_queueing_master_event_to_the_relay_log= { 0, "Queueing master event to the relay log", 0}; PSI_stage_info stage_reading_event_from_the_relay_log= { 0, "Reading event from the relay log", 0}; +PSI_stage_info stage_recreating_table= { 0, "recreating table", 0}; PSI_stage_info stage_registering_slave_on_master= { 0, "Registering slave on master", 0}; PSI_stage_info stage_removing_duplicates= { 0, "Removing duplicates", 0}; PSI_stage_info stage_removing_tmp_table= { 0, "removing tmp table", 0}; @@ -9455,6 +9466,8 @@ PSI_stage_info stage_gtid_wait_other_connection= { 0, "Waiting for other master PSI_stage_info *all_server_stages[]= { & stage_after_create, + & stage_after_opening_tables, + & stage_after_table_lock, & stage_allocating_local_table, & stage_alter_inplace, & stage_alter_inplace_commit, @@ -9486,6 +9499,7 @@ PSI_stage_info *all_server_stages[]= & stage_executing, & stage_execution_of_init_command, & stage_explaining, + & stage_finding_key_cache, & stage_finished_reading_one_binlog_switching_to_next_binlog, & stage_flushing_relay_log_and_master_info_repository, & stage_flushing_relay_log_info_file, @@ -9510,6 +9524,7 @@ PSI_stage_info *all_server_stages[]= & stage_query_end, & stage_queueing_master_event_to_the_relay_log, & stage_reading_event_from_the_relay_log, + & stage_recreating_table, & stage_registering_slave_on_master, & stage_removing_duplicates, & stage_removing_tmp_table, @@ -9617,23 +9632,49 @@ void init_server_psi_keys(void) category= "com"; init_com_statement_info(); - count= array_elements(com_statement_info); + + /* + Register [0 .. COM_QUERY - 1] as "statement/com/..." + */ + count= (int) COM_QUERY; mysql_statement_register(category, com_statement_info, count); /* + Register [COM_QUERY + 1 .. COM_END] as "statement/com/..." + */ + count= (int) COM_END - (int) COM_QUERY; + mysql_statement_register(category, & com_statement_info[(int) COM_QUERY + 1], count); + + category= "abstract"; + /* + Register [COM_QUERY] as "statement/abstract/com_query" + */ + mysql_statement_register(category, & com_statement_info[(int) COM_QUERY], 1); + + /* When a new packet is received, - it is instrumented as "statement/com/". + it is instrumented as "statement/abstract/new_packet". Based on the packet type found, it later mutates to the proper narrow type, for example - "statement/com/query" or "statement/com/ping". - In cases of "statement/com/query", SQL queries are given to + "statement/abstract/query" or "statement/com/ping". + In cases of "statement/abstract/query", SQL queries are given to the parser, which mutates the statement type to an even more narrow classification, for example "statement/sql/select". */ stmt_info_new_packet.m_key= 0; - stmt_info_new_packet.m_name= ""; + stmt_info_new_packet.m_name= "new_packet"; stmt_info_new_packet.m_flags= PSI_FLAG_MUTABLE; - mysql_statement_register(category, & stmt_info_new_packet, 1); + mysql_statement_register(category, &stmt_info_new_packet, 1); + + /* + Statements processed from the relay log are initially instrumented as + "statement/abstract/relay_log". The parser will mutate the statement type to + a more specific classification, for example "statement/sql/insert". + */ + stmt_info_rpl.m_key= 0; + stmt_info_rpl.m_name= "relay_log"; + stmt_info_rpl.m_flags= PSI_FLAG_MUTABLE; + mysql_statement_register(category, &stmt_info_rpl, 1); #endif } diff --git a/sql/mysqld.h b/sql/mysqld.h index 0e3af959122..e7eea3dfa1a 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -333,6 +333,8 @@ void init_server_psi_keys(); Hint: grep PSI_stage_info | sort -u */ extern PSI_stage_info stage_after_create; +extern PSI_stage_info stage_after_opening_tables; +extern PSI_stage_info stage_after_table_lock; extern PSI_stage_info stage_allocating_local_table; extern PSI_stage_info stage_alter_inplace_prepare; extern PSI_stage_info stage_alter_inplace; @@ -361,6 +363,7 @@ extern PSI_stage_info stage_enabling_keys; extern PSI_stage_info stage_executing; extern PSI_stage_info stage_execution_of_init_command; extern PSI_stage_info stage_explaining; +extern PSI_stage_info stage_finding_key_cache; extern PSI_stage_info stage_finished_reading_one_binlog_switching_to_next_binlog; extern PSI_stage_info stage_flushing_relay_log_and_master_info_repository; extern PSI_stage_info stage_flushing_relay_log_info_file; @@ -385,6 +388,7 @@ extern PSI_stage_info stage_purging_old_relay_logs; extern PSI_stage_info stage_query_end; extern PSI_stage_info stage_queueing_master_event_to_the_relay_log; extern PSI_stage_info stage_reading_event_from_the_relay_log; +extern PSI_stage_info stage_recreating_table; extern PSI_stage_info stage_registering_slave_on_master; extern PSI_stage_info stage_removing_duplicates; extern PSI_stage_info stage_removing_tmp_table; @@ -461,6 +465,11 @@ extern PSI_statement_info sql_statement_info[(uint) SQLCOM_END + 1]; */ extern PSI_statement_info com_statement_info[(uint) COM_END + 1]; +/** + Statement instrumentation key for replication. +*/ +extern PSI_statement_info stmt_info_rpl; + void init_sql_statement_info(); void init_com_statement_info(); #endif /* HAVE_PSI_STATEMENT_INTERFACE */ @@ -618,7 +627,7 @@ extern my_atomic_rwlock_t statistics_lock; void unireg_end(void) __attribute__((noreturn)); /* increment query_id and return it. */ -inline query_id_t next_query_id() +inline __attribute__((warn_unused_result)) query_id_t next_query_id() { query_id_t id; my_atomic_rwlock_wrlock(&global_query_id_lock); diff --git a/sql/password.c b/sql/password.c index 7a3d8aafde3..37d06136d80 100644 --- a/sql/password.c +++ b/sql/password.c @@ -442,7 +442,7 @@ void make_scrambled_password(char *to, const char *password) /* Produce an obscure octet sequence from password and random - string, recieved from the server. This sequence corresponds to the + string, received from the server. This sequence corresponds to the password, but password can not be easily restored from it. The sequence is then sent to the server for validation. Trailing zero is not stored in the buf as it is not needed. @@ -476,7 +476,7 @@ scramble(char *to, const char *message, const char *password) /* Check that scrambled message corresponds to the password; the function - is used by server to check that recieved reply is authentic. + is used by server to check that received reply is authentic. This function does not check lengths of given strings: message must be null-terminated, reply and hash_stage2 must be at least SHA1_HASH_SIZE long (if not, something fishy is going on). diff --git a/sql/protocol.cc b/sql/protocol.cc index effeee9b4aa..2400dadfadc 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -64,7 +64,7 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length) /* - net_store_data() - extended version with character set conversion. + net_store_data_cs() - extended version with character set conversion. It is optimized for short strings whose length after conversion is garanteed to be less than 251, which accupies @@ -76,8 +76,12 @@ bool Protocol_binary::net_store_data(const uchar *from, size_t length) */ #ifndef EMBEDDED_LIBRARY -bool Protocol::net_store_data(const uchar *from, size_t length, +bool Protocol::net_store_data_cs(const uchar *from, size_t length, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) +#else +bool Protocol_binary::net_store_data_cs(const uchar *from, size_t length, + CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) +#endif { uint dummy_errors; /* Calculate maxumum possible result length */ @@ -117,7 +121,6 @@ bool Protocol::net_store_data(const uchar *from, size_t length, packet->length((uint) (to - packet->ptr())); return 0; } -#endif /** @@ -1007,7 +1010,7 @@ bool Protocol::store_string_aux(const char *from, size_t length, tocs != &my_charset_bin) { /* Store with conversion */ - return net_store_data((uchar*) from, length, fromcs, tocs); + return net_store_data_cs((uchar*) from, length, fromcs, tocs); } /* Store without conversion */ return net_store_data((uchar*) from, length); diff --git a/sql/protocol.h b/sql/protocol.h index 1c0a28560bd..c58de68289f 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -44,8 +44,12 @@ protected: uint field_count; #ifndef EMBEDDED_LIBRARY bool net_store_data(const uchar *from, size_t length); + bool net_store_data_cs(const uchar *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); #else virtual bool net_store_data(const uchar *from, size_t length); + virtual bool net_store_data_cs(const uchar *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); char **next_field; MYSQL_FIELD *next_mysql_field; MEM_ROOT *alloc; @@ -54,8 +58,6 @@ protected: The following two are low-level functions that are invoked from higher-level store_xxx() funcs. The data is stored into this->packet. */ - bool net_store_data(const uchar *from, size_t length, - CHARSET_INFO *fromcs, CHARSET_INFO *tocs); bool store_string_aux(const char *from, size_t length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); @@ -184,6 +186,8 @@ public: #ifdef EMBEDDED_LIBRARY virtual bool write(); bool net_store_data(const uchar *from, size_t length); + bool net_store_data_cs(const uchar *from, size_t length, + CHARSET_INFO *fromcs, CHARSET_INFO *tocs); #endif virtual bool store_null(); virtual bool store_tiny(longlong from); diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index fcb6a849fb1..05227a29775 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -1229,7 +1229,7 @@ bool Deferred_log_events::execute(rpl_group_info *rgi) void Deferred_log_events::rewind() { /* - Reset preceeding Query log event events which execution was + Reset preceding Query log event events which execution was deferred because of slave side filtering. */ if (!is_empty()) diff --git a/sql/share/charsets/Index.xml b/sql/share/charsets/Index.xml index 3e402226a34..9764d629625 100644 --- a/sql/share/charsets/Index.xml +++ b/sql/share/charsets/Index.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003-2005 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/ascii.xml b/sql/share/charsets/ascii.xml index 29336b3a665..c516a68516c 100644 --- a/sql/share/charsets/ascii.xml +++ b/sql/share/charsets/ascii.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003, 2007 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/cp1250.xml b/sql/share/charsets/cp1250.xml index 1b4a71ef6d5..e6681a625a2 100644 --- a/sql/share/charsets/cp1250.xml +++ b/sql/share/charsets/cp1250.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003, 2005 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/cp1256.xml b/sql/share/charsets/cp1256.xml index 806fef961f7..ab0ba855f3b 100644 --- a/sql/share/charsets/cp1256.xml +++ b/sql/share/charsets/cp1256.xml @@ -6,6 +6,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/cp1257.xml b/sql/share/charsets/cp1257.xml index 8ae73fdf25a..61d1d276b0a 100644 --- a/sql/share/charsets/cp1257.xml +++ b/sql/share/charsets/cp1257.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/cp850.xml b/sql/share/charsets/cp850.xml index 198b336daef..06465540a75 100644 --- a/sql/share/charsets/cp850.xml +++ b/sql/share/charsets/cp850.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/cp866.xml b/sql/share/charsets/cp866.xml index d35f3d68b05..9cd8c8c504b 100644 --- a/sql/share/charsets/cp866.xml +++ b/sql/share/charsets/cp866.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/dec8.xml b/sql/share/charsets/dec8.xml index 66bb421b674..68949309ced 100644 --- a/sql/share/charsets/dec8.xml +++ b/sql/share/charsets/dec8.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/geostd8.xml b/sql/share/charsets/geostd8.xml index a789d07e6d8..822cc083724 100644 --- a/sql/share/charsets/geostd8.xml +++ b/sql/share/charsets/geostd8.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/greek.xml b/sql/share/charsets/greek.xml index 5b66a7ab442..cbbe22e675a 100644 --- a/sql/share/charsets/greek.xml +++ b/sql/share/charsets/greek.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/hebrew.xml b/sql/share/charsets/hebrew.xml index 0544b27ef4f..562fa4f4748 100644 --- a/sql/share/charsets/hebrew.xml +++ b/sql/share/charsets/hebrew.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003, 2006 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/hp8.xml b/sql/share/charsets/hp8.xml index 83a076237f7..b17f75ed73e 100644 --- a/sql/share/charsets/hp8.xml +++ b/sql/share/charsets/hp8.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/keybcs2.xml b/sql/share/charsets/keybcs2.xml index a9f305deab8..7c2775ba5c3 100644 --- a/sql/share/charsets/keybcs2.xml +++ b/sql/share/charsets/keybcs2.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/koi8r.xml b/sql/share/charsets/koi8r.xml index 21ebf78b79e..25264d4f9ce 100644 --- a/sql/share/charsets/koi8r.xml +++ b/sql/share/charsets/koi8r.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/koi8u.xml b/sql/share/charsets/koi8u.xml index 65145c97593..a2f5de9feb2 100644 --- a/sql/share/charsets/koi8u.xml +++ b/sql/share/charsets/koi8u.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/languages.html b/sql/share/charsets/languages.html index 2b1c44421bf..3263d6a2ae2 100644 --- a/sql/share/charsets/languages.html +++ b/sql/share/charsets/languages.html @@ -1,6 +1,7 @@ #!/bin/sh # Copyright (C) 2003 MySQL AB +# Use is subject to license terms # # 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 diff --git a/sql/share/charsets/latin1.xml b/sql/share/charsets/latin1.xml index 4054eea8d33..68307847d91 100644 --- a/sql/share/charsets/latin1.xml +++ b/sql/share/charsets/latin1.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003, 2005 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/latin2.xml b/sql/share/charsets/latin2.xml index a44ec7e0ec6..29ff4cb974b 100644 --- a/sql/share/charsets/latin2.xml +++ b/sql/share/charsets/latin2.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003, 2005 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/latin5.xml b/sql/share/charsets/latin5.xml index 6b60e58cdda..ca7dd106de5 100644 --- a/sql/share/charsets/latin5.xml +++ b/sql/share/charsets/latin5.xml @@ -4,6 +4,7 @@ <copyright> Copyright (c) 2003, 2005 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/latin7.xml b/sql/share/charsets/latin7.xml index fb384b3a5ff..81866c23bbd 100644 --- a/sql/share/charsets/latin7.xml +++ b/sql/share/charsets/latin7.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/macce.xml b/sql/share/charsets/macce.xml index d7242f26297..4fa46301d2e 100644 --- a/sql/share/charsets/macce.xml +++ b/sql/share/charsets/macce.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/macroman.xml b/sql/share/charsets/macroman.xml index a2485cf9379..4ee8dc1f952 100644 --- a/sql/share/charsets/macroman.xml +++ b/sql/share/charsets/macroman.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/charsets/swe7.xml b/sql/share/charsets/swe7.xml index f12a2238718..d881f1e7d62 100644 --- a/sql/share/charsets/swe7.xml +++ b/sql/share/charsets/swe7.xml @@ -4,6 +4,7 @@ <copyright> Copyright (C) 2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index dc50c68bcdd..ed7976e2abd 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6911,6 +6911,49 @@ ER_MTS_EVENT_BIGGER_PENDING_JOBS_SIZE_MAX ER_INNODB_NO_FT_USES_PARSER eng "Cannot CREATE FULLTEXT INDEX WITH PARSER on InnoDB table" +ER_BINLOG_LOGICAL_CORRUPTION + eng "The binary log file '%s' is logically corrupted: %s" + +ER_WARN_PURGE_LOG_IN_USE + eng "file %s was not purged because it was being read by %d thread(s), purged only %d out of %d files." + +ER_WARN_PURGE_LOG_IS_ACTIVE + eng "file %s was not purged because it is the active log file." + +ER_AUTO_INCREMENT_CONFLICT + eng "Auto-increment value in UPDATE conflicts with internally generated values" + +WARN_ON_BLOCKHOLE_IN_RBR + eng "Row events are not logged for %s statements that modify BLACKHOLE tables in row format. Table(s): '%-.192s'" + +ER_SLAVE_MI_INIT_REPOSITORY + eng "Slave failed to initialize master info structure from the repository" + +ER_SLAVE_RLI_INIT_REPOSITORY + eng "Slave failed to initialize relay log info structure from the repository" + +ER_ACCESS_DENIED_CHANGE_USER_ERROR 28000 + eng "Access denied trying to change to user '%-.48s'@'%-.64s' (using password: %s). Disconnecting." + bgn "Отказан достъп при опит за смяна към потребител %-.48s'@'%-.64s' (използвана парола: %s). Затваряне на връзката." + +ER_INNODB_READ_ONLY + eng "InnoDB is in read only mode." + +ER_STOP_SLAVE_SQL_THREAD_TIMEOUT + eng "STOP SLAVE command execution is incomplete: Slave SQL thread got the stop signal, thread is busy, SQL thread will stop once the current task is complete." + +ER_STOP_SLAVE_IO_THREAD_TIMEOUT + eng "STOP SLAVE command execution is incomplete: Slave IO thread got the stop signal, thread is busy, IO thread will stop once the current task is complete." + +ER_TABLE_CORRUPT + eng "Operation cannot be performed. The table '%-.64s.%-.64s' is missing, corrupt or contains bad data." + +ER_TEMP_FILE_WRITE_FAILURE + eng "Temporary file write failure." + +ER_INNODB_FT_AUX_NOT_HEX_ID + eng "Upgrade index name failed, please use create index(alter table) algorithm copy to rebuild index." + # # MariaDB error messages section starts here diff --git a/sql/slave.cc b/sql/slave.cc index a40e5735b24..f7d019a6c39 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4427,7 +4427,7 @@ pthread_handler_t handle_slave_sql(void *arg) /* binlog_annotate_row_events must be TRUE only after an Annotate_rows event - has been recieved and only till the last corresponding rbr event has been + has been received and only till the last corresponding rbr event has been applied. In all other cases it must be FALSE. */ thd->variables.binlog_annotate_row_events= 0; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 89248f5746b..8a9e8ddc816 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1157,6 +1157,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) LEX *old_lex; Item_change_list old_change_list; String old_packet; + uint old_server_status; Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer; Object_creation_ctx *saved_creation_ctx; Diagnostics_area *da= thd->get_stmt_da(); @@ -1290,6 +1291,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) It is probably safe to use same thd->convert_buff everywhere. */ old_packet.swap(thd->packet); + old_server_status= thd->server_status; /* Switch to per-instruction arena here. We can do it since we cleanup @@ -1410,6 +1412,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) thd->spcont->pop_all_cursors(); // To avoid memory leaks after an error /* Restore all saved */ + thd->server_status= old_server_status; old_packet.swap(thd->packet); DBUG_ASSERT(thd->change_list.is_empty()); old_change_list.move_elements_to(&thd->change_list); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index c4c06ba0e0b..5f077c22168 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -10841,7 +10841,6 @@ struct MPVIO_EXT :public MYSQL_PLUGIN_VIO uint pkt_len; } cached_server_packet; int packets_read, packets_written; ///< counters for send/received packets - uint connect_errors; ///< if there were connect errors for this host bool make_it_fail; /** when plugin returns a failure this tells us what really happened */ enum { SUCCESS, FAILURE, RESTART } status; @@ -11392,9 +11391,6 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, */ DBUG_ASSERT(net->read_pos[pkt_len] == 0); - if (mpvio->connect_errors) - reset_host_connect_errors(thd->main_security_ctx.ip); - ulong client_capabilities= uint2korr(net->read_pos); if (client_capabilities & CLIENT_PROTOCOL_41) { @@ -11972,8 +11968,6 @@ static int do_auth_once(THD *thd, const LEX_STRING *auth_plugin_name, Perform the handshake, authorize the client and update thd sctx variables. @param thd thread handle - @param connect_errors number of previous failed connect attemps - from this host @param com_change_user_pkt_len size of the COM_CHANGE_USER packet (without the first, command, byte) or 0 if it's not a COM_CHANGE_USER (that is, if @@ -11982,8 +11976,7 @@ static int do_auth_once(THD *thd, const LEX_STRING *auth_plugin_name, @retval 0 success, thd is updated. @retval 1 error */ -bool acl_authenticate(THD *thd, uint connect_errors, - uint com_change_user_pkt_len) +bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) { int res= CR_OK; MPVIO_EXT mpvio; @@ -11997,7 +11990,6 @@ bool acl_authenticate(THD *thd, uint connect_errors, mpvio.write_packet= server_mpvio_write_packet; mpvio.info= server_mpvio_info; mpvio.thd= thd; - mpvio.connect_errors= connect_errors; mpvio.status= MPVIO_EXT::FAILURE; mpvio.make_it_fail= false; mpvio.auth_info.host_or_ip= thd->security_ctx->host_or_ip; diff --git a/sql/sql_acl.h b/sql/sql_acl.h index df523fae1ca..1aeb123153e 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -202,7 +202,7 @@ my_bool acl_reload(THD *thd); void acl_free(bool end=0); ulong acl_get(const char *host, const char *ip, const char *user, const char *db, my_bool db_is_pattern); -bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len); +bool acl_authenticate(THD *thd, uint com_change_user_pkt_len); bool acl_getroot(Security_context *sctx, char *user, char *host, char *ip, char *db); bool acl_check_host(const char *host, const char *ip); diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 41808bc2717..34a076cc327 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. - Copyright (c) 2012, 2013, Monty Program Ab. +/* Copyright (c) 2010, 2014, Oracle and/or its affiliates. + Copyright (c) 2012, 2014, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -55,7 +55,7 @@ static bool admin_recreate_table(THD *thd, TABLE_LIST *table_list) DEBUG_SYNC(thd, "ha_admin_try_alter"); tmp_disable_binlog(thd); // binlogging is done by caller if wanted result_code= (open_temporary_tables(thd, table_list) || - mysql_recreate_table(thd, table_list)); + mysql_recreate_table(thd, table_list, false)); reenable_binlog(thd); /* mysql_recreate_table() can push OK or ERROR. @@ -719,7 +719,9 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (result_code == HA_ADMIN_OK) { DBUG_PRINT("admin", ("calling operator_func '%s'", operator_name)); + THD_STAGE_INFO(thd, stage_executing); result_code = (table->table->file->*operator_func)(thd, check_opt); + THD_STAGE_INFO(thd, stage_sending_data); DBUG_PRINT("admin", ("operator_func returned: %d", result_code)); } @@ -862,7 +864,7 @@ send_result_message: } if (protocol->write()) goto err; - + THD_STAGE_INFO(thd, stage_recreating_table); DBUG_PRINT("info", ("HA_ADMIN_TRY_ALTER, trying analyze...")); TABLE_LIST *save_next_local= table->next_local, *save_next_global= table->next_global; @@ -1080,6 +1082,7 @@ bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables, KEY_CACHE *key_cache; DBUG_ENTER("mysql_assign_to_keycache"); + THD_STAGE_INFO(thd, stage_finding_key_cache); check_opt.init(); mysql_mutex_lock(&LOCK_global_system_variables); if (!(key_cache= get_key_cache(key_cache_name))) @@ -1196,7 +1199,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res= (specialflag & SPECIAL_NO_NEW_FUNC) ? - mysql_recreate_table(thd, first_table) : + mysql_recreate_table(thd, first_table, true) : mysql_admin_table(thd, first_table, &m_lex->check_opt, "optimize", TL_WRITE, 1, 0, 0, 0, &handler::ha_optimize, 0); diff --git a/sql/sql_alter.h b/sql/sql_alter.h index f0c0a873a5c..526442e83e2 100644 --- a/sql/sql_alter.h +++ b/sql/sql_alter.h @@ -1,4 +1,5 @@ -/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 2014, Oracle and/or its affiliates. + Copyright (c) 2013, 2014, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -73,6 +74,7 @@ public: static const uint ALTER_CONVERT = 1L << 10; // Set for FORCE + // Set for ENGINE(same engine) // Set by mysql_recreate_table() static const uint ALTER_RECREATE = 1L << 11; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f30b2617c1d..055806609e7 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -883,6 +883,8 @@ void close_thread_tables(THD *thd) TABLE *table; DBUG_ENTER("close_thread_tables"); + THD_STAGE_INFO(thd, stage_closing_tables); + #ifdef EXTRA_DEBUG DBUG_PRINT("tcache", ("open tables:")); for (table= thd->open_tables; table; table= table->next) @@ -4584,6 +4586,7 @@ restart: } err: + THD_STAGE_INFO(thd, stage_after_opening_tables); free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block if (error && *table_to_open) @@ -5036,6 +5039,7 @@ end: trans_rollback_stmt(thd); close_thread_tables(thd); } + THD_STAGE_INFO(thd, stage_after_opening_tables); DBUG_RETURN(table); } @@ -8362,6 +8366,75 @@ void wrap_ident(THD *thd, Item **conds) thd->restore_active_arena(arena, &backup); } +/** + Prepare ON expression + + @param thd Thread handle + @param table Pointer to table list + @param is_update Update flag + + @retval TRUE error. + @retval FALSE OK. +*/ + +bool setup_on_expr(THD *thd, TABLE_LIST *table, bool is_update) +{ + uchar buff[STACK_BUFF_ALLOC]; // Max argument in function + if (check_stack_overrun(thd, STACK_MIN_SIZE, buff)) + return TRUE; // Fatal error flag is set! + for(; table; table= table->next_local) + { + TABLE_LIST *embedded; /* The table at the current level of nesting. */ + TABLE_LIST *embedding= table; /* The parent nested table reference. */ + do + { + embedded= embedding; + DBUG_PRINT("XXX", ("check: %s", table->alias)); + if (embedded->on_expr) + { + thd->where="on clause"; + embedded->on_expr->mark_as_condition_AND_part(embedded); + if ((!embedded->on_expr->fixed && + embedded->on_expr->fix_fields(thd, &embedded->on_expr)) || + embedded->on_expr->check_cols(1)) + return TRUE; + } + /* + If it's a semi-join nest, fix its "left expression", as it is used by + the SJ-Materialization + */ + if (embedded->sj_subq_pred) + { + Item **left_expr= &embedded->sj_subq_pred->left_expr; + if (!(*left_expr)->fixed && (*left_expr)->fix_fields(thd, left_expr)) + return TRUE; + } + + embedding= embedded->embedding; + } + while (embedding && + embedding->nested_join->join_list.head() == embedded); + + if (table->is_merged_derived()) + { + SELECT_LEX *select_lex= table->get_single_select(); + setup_on_expr(thd, select_lex->get_table_list(), is_update); + } + + /* process CHECK OPTION */ + if (is_update) + { + TABLE_LIST *view= table->top_table(); + if (view->effective_with_check) + { + if (view->prepare_check_option(thd)) + return TRUE; + thd->change_item_tree(&table->check_option, view->check_option); + } + } + } + return FALSE; +} /* Fix all conditions and outer join expressions. @@ -8386,7 +8459,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves, { SELECT_LEX *select_lex= thd->lex->current_select; TABLE_LIST *table= NULL; // For HP compilers - List_iterator<TABLE_LIST> ti(leaves); /* it_is_update set to TRUE when tables of primary SELECT_LEX (SELECT_LEX which belong to LEX, i.e. most up SELECT) will be updated by @@ -8445,51 +8517,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves, Apply fix_fields() to all ON clauses at all levels of nesting, including the ones inside view definitions. */ - while ((table= ti++)) - { - TABLE_LIST *embedded; /* The table at the current level of nesting. */ - TABLE_LIST *embedding= table; /* The parent nested table reference. */ - do - { - embedded= embedding; - if (embedded->on_expr) - { - /* Make a join an a expression */ - thd->where="on clause"; - embedded->on_expr->mark_as_condition_AND_part(embedded); - if ((!embedded->on_expr->fixed && - embedded->on_expr->fix_fields(thd, &embedded->on_expr)) || - embedded->on_expr->check_cols(1)) - goto err_no_arena; - } - /* - If it's a semi-join nest, fix its "left expression", as it is used by - the SJ-Materialization - */ - if (embedded->sj_subq_pred) - { - Item **left_expr= &embedded->sj_subq_pred->left_expr; - if (!(*left_expr)->fixed && (*left_expr)->fix_fields(thd, left_expr)) - goto err_no_arena; - } - - embedding= embedded->embedding; - } - while (embedding && - embedding->nested_join->join_list.head() == embedded); - - /* process CHECK OPTION */ - if (it_is_update) - { - TABLE_LIST *view= table->top_table(); - if (view->effective_with_check) - { - if (view->prepare_check_option(thd)) - goto err_no_arena; - thd->change_item_tree(&table->check_option, view->check_option); - } - } - } + if (setup_on_expr(thd, tables, it_is_update)) + goto err_no_arena; if (!thd->stmt_arena->is_conventional()) { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c1c252955aa..a48ebd450bb 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1238,7 +1238,6 @@ Sql_condition* THD::raise_condition(uint sql_errno, got_warning= 1; break; case Sql_condition::WARN_LEVEL_ERROR: - mysql_audit_general(this, MYSQL_AUDIT_GENERAL_ERROR, sql_errno, msg); break; default: DBUG_ASSERT(FALSE); @@ -1249,6 +1248,8 @@ Sql_condition* THD::raise_condition(uint sql_errno, if (level == Sql_condition::WARN_LEVEL_ERROR) { + mysql_audit_general(this, MYSQL_AUDIT_GENERAL_ERROR, sql_errno, msg); + is_slave_error= 1; // needed to catch query errors during replication if (!da->is_error()) diff --git a/sql/sql_class.h b/sql/sql_class.h index 1c11c2f6416..5898d9e2cf8 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3063,8 +3063,11 @@ public: Clear the current error, if any. We do not clear is_fatal_error or is_fatal_sub_stmt_error since we assume this is never called if the fatal error is set. + @todo: To silence an error, one should use Internal_error_handler - mechanism. In future this function will be removed. + mechanism. Issuing an error that can be possibly later "cleared" is not + compatible with other installed error handlers and audit plugins. + In future this function will be removed. */ inline void clear_error() { diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 997fd7923a0..433f3303ad7 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -715,7 +715,7 @@ static void update_global_user_stats_with_user(THD *thd, user_stats->cpu_time+= (thd->status_var.cpu_time - thd->org_status_var.cpu_time); /* - This is handle specially as bytes_recieved is incremented BEFORE + This is handle specially as bytes_received is incremented BEFORE org_status_var is copied. */ user_stats->bytes_received+= (thd->org_status_var.bytes_received- @@ -1067,7 +1067,7 @@ static int check_connection(THD *thd) return 1; /* The error is set by alloc(). */ } - auth_rc= acl_authenticate(thd, connect_errors, 0); + auth_rc= acl_authenticate(thd, 0); if (auth_rc == 0 && connect_errors != 0) { /* diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0c4983e540d..922f0d73165 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1224,7 +1224,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, auth_rc= 1; } else - auth_rc= acl_authenticate(thd, 0, packet_length); + auth_rc= acl_authenticate(thd, packet_length); mysql_audit_notify_connection_change_user(thd); if (auth_rc) @@ -5134,7 +5134,6 @@ finish: } /* Free tables */ - THD_STAGE_INFO(thd, stage_closing_tables); close_thread_tables(thd); #ifndef DBUG_OFF diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index f4a0b84ff65..e70b9e51772 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -3207,15 +3207,21 @@ static void plugin_vars_free_values(sys_var *vars) static SHOW_TYPE pluginvar_show_type(st_mysql_sys_var *plugin_var) { - switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) { + switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_UNSIGNED)) { case PLUGIN_VAR_BOOL: return SHOW_MY_BOOL; case PLUGIN_VAR_INT: - return SHOW_INT; + return SHOW_SINT; + case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED: + return SHOW_UINT; case PLUGIN_VAR_LONG: - return SHOW_LONG; + return SHOW_SLONG; + case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED: + return SHOW_ULONG; case PLUGIN_VAR_LONGLONG: - return SHOW_LONGLONG; + return SHOW_SLONGLONG; + case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED: + return SHOW_ULONGLONG; case PLUGIN_VAR_STR: return SHOW_CHAR_PTR; case PLUGIN_VAR_ENUM: diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 6ca4015adb4..ebceae70ee5 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -74,7 +74,7 @@ When one supplies long data for a placeholder: - Server gets the long data in pieces with command type 'COM_STMT_SEND_LONG_DATA'. - - The packet recieved will have the format as: + - The packet received will have the format as: [COM_STMT_SEND_LONG_DATA:1][STMT_ID:4][parameter_number:2][data] - data from the packet is appended to the long data value buffer for this placeholder. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7d69a85a273..b88aed1f1bb 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -549,6 +549,7 @@ fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select, static void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) { + DBUG_ENTER("remove_redundant_subquery_clauses"); Item_subselect *subq_predicate= subq_select_lex->master_unit()->item; /* The removal should happen for IN, ALL, ANY and EXISTS subqueries, @@ -558,7 +559,7 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) b) SELECT a, (<single row subquery) FROM t1 */ if (subq_predicate->substype() == Item_subselect::SINGLEROW_SUBS) - return; + DBUG_VOID_RETURN; /* A subquery that is not single row should be one of IN/ALL/ANY/EXISTS. */ DBUG_ASSERT (subq_predicate->substype() == Item_subselect::EXISTS_SUBS || @@ -568,6 +569,7 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) { subq_select_lex->join->select_distinct= false; subq_select_lex->options&= ~SELECT_DISTINCT; + DBUG_PRINT("info", ("DISTINCT removed")); } /* @@ -577,8 +579,13 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) if (subq_select_lex->group_list.elements && !subq_select_lex->with_sum_func && !subq_select_lex->join->having) { + for (ORDER *ord= subq_select_lex->group_list.first; ord; ord= ord->next) + { + (*ord->item)->walk(&Item::eliminate_subselect_processor, FALSE, NULL); + } subq_select_lex->join->group_list= NULL; subq_select_lex->group_list.empty(); + DBUG_PRINT("info", ("GROUP BY removed")); } /* @@ -593,6 +600,7 @@ void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex) subq_select_lex->group_list.empty(); } */ + DBUG_VOID_RETURN; } @@ -700,7 +708,9 @@ JOIN::prepare(Item ***rref_pointer_array, if (!(select_options & OPTION_SETUP_TABLES_DONE) && setup_tables_and_check_access(thd, &select_lex->context, join_list, tables_list, select_lex->leaf_tables, - FALSE, SELECT_ACL, SELECT_ACL, FALSE)) + FALSE, SELECT_ACL, SELECT_ACL, + (thd->lex->sql_command == + SQLCOM_UPDATE_MULTI))) DBUG_RETURN(-1); /* @@ -14368,7 +14378,7 @@ optimize_cond(JOIN *join, COND *conds, conds= remove_eq_conds(thd, conds, cond_value); if (conds && conds->type() == Item::COND_ITEM && ((Item_cond*) conds)->functype() == Item_func::COND_AND_FUNC) - join->cond_equal= &((Item_cond_and*) conds)->cond_equal; + *cond_equal= &((Item_cond_and*) conds)->cond_equal; DBUG_EXECUTE("info",print_where(conds,"after remove", QT_ORDINARY);); } DBUG_RETURN(conds); @@ -21084,7 +21094,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, Item *view_ref= NULL; /* If we have found field not by its alias in select list but by its - original field name, we should additionaly check if we have conflict + original field name, we should additionally check if we have conflict for this name (in case if we would perform lookup in all tables). */ if (resolution == RESOLVED_BEHIND_ALIAS && !order_item->fixed && @@ -22107,7 +22117,7 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, We are replacing the argument of Item_func_set_user_var after its value has been read. The argument's null_value should be set by now, so we must set it explicitly for the replacement argument since the null_value - may be read without any preceeding call to val_*(). + may be read without any preceding call to val_*(). */ new_field->update_null_value(); List<Item> list; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 15d353c087a..535b113db45 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -941,9 +941,12 @@ public: is_handled= TRUE; break; + case ER_BAD_FIELD_ERROR: + case ER_SP_DOES_NOT_EXIST: case ER_NO_SUCH_TABLE: case ER_NO_SUCH_TABLE_IN_ENGINE: - /* Established behavior: warn if underlying tables are missing. */ + /* Established behavior: warn if underlying tables, columns, or functions + are missing. */ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_VIEW_INVALID, ER(ER_VIEW_INVALID), @@ -952,15 +955,6 @@ public: is_handled= TRUE; break; - case ER_SP_DOES_NOT_EXIST: - /* Established behavior: warn if underlying functions are missing. */ - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_VIEW_INVALID, - ER(ER_VIEW_INVALID), - m_top_view->get_db_name(), - m_top_view->get_table_name()); - is_handled= TRUE; - break; default: is_handled= FALSE; } @@ -3051,7 +3045,7 @@ static bool show_status_array(THD *thd, const char *wild, end= int10_to_str((long) *(uint*) value, buff, 10); break; case SHOW_SINT: - end= int10_to_str((long) *(uint*) value, buff, -10); + end= int10_to_str((long) *(int*) value, buff, -10); break; case SHOW_SLONG: end= int10_to_str(*(long*) value, buff, -10); @@ -4599,25 +4593,7 @@ end: } -/** - Trigger_error_handler is intended to intercept and silence SQL conditions - that might happen during trigger loading for SHOW statements. - The potential SQL conditions are: - - - ER_PARSE_ERROR -- this error is thrown if a trigger definition file - is damaged or contains invalid CREATE TRIGGER statement. That should - not happen in normal life. - - - ER_TRG_NO_DEFINER -- this warning is thrown when we're loading a - trigger created/imported in/from the version of MySQL, which does not - support trigger definers. - - - ER_TRG_NO_CREATION_CTX -- this warning is thrown when we're loading a - trigger created/imported in/from the version of MySQL, which does not - support trigger creation contexts. -*/ - -class Trigger_error_handler : public Internal_error_handler +class Warnings_only_error_handler : public Internal_error_handler { public: bool handle_condition(THD *thd, @@ -4632,12 +4608,16 @@ public: sql_errno == ER_TRG_NO_CREATION_CTX) return true; - return false; + if (level != Sql_condition::WARN_LEVEL_ERROR) + return false; + + if (!thd->get_stmt_da()->is_error()) + thd->get_stmt_da()->set_error_status(sql_errno, msg, sqlstate, *cond_hdl); + return true; // handled! } }; - /** @brief Fill I_S tables whose data are retrieved from frm files and storage engine @@ -4847,25 +4827,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) if (!(table_open_method & ~OPEN_FRM_ONLY) && db_name != &INFORMATION_SCHEMA_NAME) { - /* - Here we need to filter out warnings, which can happen - during loading of triggers in fill_schema_table_from_frm(), - because we don't need those warnings to pollute output of - SELECT from I_S / SHOW-statements. - */ - - Trigger_error_handler err_handler; - thd->push_internal_handler(&err_handler); - - int res= fill_schema_table_from_frm(thd, tables, schema_table, - db_name, table_name, - schema_table_idx, - &open_tables_state_backup, - can_deadlock); - - thd->pop_internal_handler(); - - if (!res) + if (!fill_schema_table_from_frm(thd, tables, schema_table, + db_name, table_name, + schema_table_idx, + &open_tables_state_backup, + can_deadlock)) continue; } @@ -8013,95 +7979,6 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, } -/** - Fill INFORMATION_SCHEMA-table, leave correct Diagnostics_area / - Warning_info state after itself. - - This function is a wrapper around ST_SCHEMA_TABLE::fill_table(), which - may "partially silence" some errors. The thing is that during - fill_table() many errors might be emitted. These errors stem from the - nature of fill_table(). - - For example, SELECT ... FROM INFORMATION_SCHEMA.xxx WHERE TABLE_NAME = 'xxx' - results in a number of 'Table <db name>.xxx does not exist' errors, - because fill_table() tries to open the 'xxx' table in every possible - database. - - Those errors are cleared (the error status is cleared from - Diagnostics_area) inside fill_table(), but they remain in Warning_info - (Warning_info is not cleared because it may contain useful warnings). - - This function is responsible for making sure that Warning_info does not - contain warnings corresponding to the cleared errors. - - @note: THD::no_warnings_for_error used to be set before calling - fill_table(), thus those errors didn't go to Warning_info. This is not - the case now (THD::no_warnings_for_error was eliminated as a hack), so we - need to take care of those warnings here. - - @param thd Thread context. - @param table_list I_S table. - @param join_table JOIN/SELECT table. - - @return Error status. - @retval TRUE Error. - @retval FALSE Success. -*/ -static bool do_fill_table(THD *thd, - TABLE_LIST *table_list, - JOIN_TAB *join_table) -{ - // NOTE: fill_table() may generate many "useless" warnings, which will be - // ignored afterwards. On the other hand, there might be "useful" - // warnings, which should be presented to the user. Warning_info usually - // stores no more than THD::variables.max_error_count warnings. - // The problem is that "useless warnings" may occupy all the slots in the - // Warning_info, so "useful warnings" get rejected. In order to avoid - // that problem we create a Warning_info instance, which is capable of - // storing "unlimited" number of warnings. - Diagnostics_area *da= thd->get_stmt_da(); - Warning_info wi_tmp(thd->query_id, true, true); - - da->push_warning_info(&wi_tmp); - - Item *item= join_table->select_cond; - if (join_table->cache_select && - join_table->cache_select->cond) - { - /* - If join buffering is used, we should use the condition that is attached - to the join cache. Cache condition has a part of WHERE that can be - checked when we're populating this table. - join_tab->select_cond is of no interest, because it only has conditions - that depend on both this table and previous tables in the join order. - */ - item= join_table->cache_select->cond; - } - bool res= table_list->schema_table->fill_table(thd, table_list, item); - - da->pop_warning_info(); - - // Pass an error if any. - - if (da->is_error()) - { - da->push_warning(thd, - da->sql_errno(), - da->get_sqlstate(), - Sql_condition::WARN_LEVEL_ERROR, - da->message()); - } - - // Pass warnings (if any). - // - // Filter out warnings with WARN_LEVEL_ERROR level, because they - // correspond to the errors which were filtered out in fill_table(). - da->copy_non_errors_from_wi(thd, &wi_tmp); - - return res; -} - - /* Fill temporary schema tables before SELECT @@ -8121,8 +7998,13 @@ bool get_schema_tables_result(JOIN *join, THD *thd= join->thd; LEX *lex= thd->lex; bool result= 0; + const char *old_proc_info; DBUG_ENTER("get_schema_tables_result"); + Warnings_only_error_handler err_handler; + thd->push_internal_handler(&err_handler); + old_proc_info= thd_proc_info(thd, "Filling schema table"); + for (JOIN_TAB *tab= first_linear_tab(join, WITH_CONST_TABLES); tab; tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS)) @@ -8175,20 +8057,56 @@ bool get_schema_tables_result(JOIN *join, else table_list->table->file->stats.records= 0; - if (do_fill_table(thd, table_list, tab)) + + Item *cond= tab->select_cond; + if (tab->cache_select && tab->cache_select->cond) + { + /* + If join buffering is used, we should use the condition that is + attached to the join cache. Cache condition has a part of WHERE that + can be checked when we're populating this table. + join_tab->select_cond is of no interest, because it only has + conditions that depend on both this table and previous tables in the + join order. + */ + cond= tab->cache_select->cond; + } + + if (table_list->schema_table->fill_table(thd, table_list, cond)) { result= 1; join->error= 1; tab->read_record.table->file= table_list->table->file; table_list->schema_table_state= executed_place; - if (!thd->is_error()) - my_error(ER_UNKNOWN_ERROR, MYF(0)); break; } tab->read_record.table->file= table_list->table->file; table_list->schema_table_state= executed_place; } } + thd->pop_internal_handler(); + if (thd->is_error()) + { + /* + This hack is here, because I_S code uses thd->clear_error() a lot. + Which means, a Warnings_only_error_handler cannot handle the error + corectly as it does not know whether an error is real (e.g. caused + by tab->select_cond->val_int()) or will be cleared later. + Thus it ignores all errors, and the real one (that is, the error + that was not cleared) is pushed now. + + It also means that an audit plugin cannot process the error correctly + either. See also thd->clear_error() + */ + thd->get_stmt_da()->push_warning(thd, + thd->get_stmt_da()->sql_errno(), + thd->get_stmt_da()->get_sqlstate(), + Sql_condition::WARN_LEVEL_ERROR, + thd->get_stmt_da()->message()); + } + else if (result) + my_error(ER_UNKNOWN_ERROR, MYF(0)); + thd_proc_info(thd, old_proc_info); DBUG_RETURN(result); } diff --git a/sql/sql_state.c b/sql/sql_state.c index c733d4b37c0..2bfd61d6696 100644 --- a/sql/sql_state.c +++ b/sql/sql_state.c @@ -1,4 +1,5 @@ /* Copyright (C) 2000-2003 MySQL AB + Use is subject to license terms 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 diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 502f1b30e8f..8af77d929ea 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1,6 +1,6 @@ /* - Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2010, 2013, Monty Program Ab. + Copyright (c) 2000, 2014, Oracle and/or its affiliates. + Copyright (c) 2010, 2014, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -6051,6 +6051,9 @@ static bool fill_alter_inplace_info(THD *thd, ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_REMOVE_PARTITIONING; if (alter_info->flags & Alter_info::ALTER_ALL_PARTITION) ha_alter_info->handler_flags|= Alter_inplace_info::ALTER_ALL_PARTITION; + /* Check for: ALTER TABLE FORCE, ALTER TABLE ENGINE and OPTIMIZE TABLE. */ + if (alter_info->flags & Alter_info::ALTER_RECREATE) + ha_alter_info->handler_flags|= Alter_inplace_info::RECREATE_TABLE; /* If we altering table with old VARCHAR fields we will be automatically @@ -6734,12 +6737,8 @@ static bool is_inplace_alter_impossible(TABLE *table, if (table->s->tmp_table) DBUG_RETURN(true); - /* - We also test if OPTIMIZE TABLE was given and was mapped to alter table. - In that case we always do full copy (ALTER_RECREATE is set in this case). - - For the ALTER TABLE tbl_name ORDER BY ... we also always use copy + For the ALTER TABLE tbl_name ORDER BY ... we always use copy algorithm. In theory, this operation can be done in-place by some engine, but since a) no current engine does this and b) our current API lacks infrastructure for passing information about table ordering @@ -6749,26 +6748,17 @@ static bool is_inplace_alter_impossible(TABLE *table, not supported for in-place in combination with other operations. Alone, it will be done by simple_rename_or_index_change(). */ - if (alter_info->flags & (Alter_info::ALTER_RECREATE | - Alter_info::ALTER_ORDER | + if (alter_info->flags & (Alter_info::ALTER_ORDER | Alter_info::ALTER_KEYS_ONOFF)) DBUG_RETURN(true); /* - Test also that engine was not given during ALTER TABLE, or - we are force to run regular alter table (copy). - E.g. ALTER TABLE tbl_name ENGINE=MyISAM. - Note that in addition to checking flag in HA_CREATE_INFO we - also check HA_CREATE_INFO::db_type value. This is done - to cover cases in which engine is changed implicitly - (e.g. when non-partitioned table becomes partitioned). - - Note that we do copy even if the table is already using the - given engine. Many users and tools depend on using ENGINE - to force a table rebuild. + If the table engine is changed explicitly (using ENGINE clause) + or implicitly (e.g. when non-partitioned table becomes + partitioned) a regular alter table (copy) needs to be + performed. */ - if (create_info->db_type != table->s->db_type() || - create_info->used_fields & HA_CREATE_USED_ENGINE) + if (create_info->db_type != table->s->db_type()) DBUG_RETURN(true); /* @@ -8498,6 +8488,15 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, } /* + ALTER TABLE ... ENGINE to the same engine is a common way to + request table rebuild. Set ALTER_RECREATE flag to force table + rebuild. + */ + if (create_info->db_type == table->s->db_type() && + create_info->used_fields & HA_CREATE_USED_ENGINE) + alter_info->flags|= Alter_info::ALTER_RECREATE; + + /* If the old table had partitions and we are doing ALTER TABLE ... engine= <new_engine>, the new table must preserve the original partitioning. This means that the new engine is still the @@ -9465,12 +9464,14 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, mysql_recreate_table() thd Thread handler tables Tables to recreate + table_copy Recreate the table by using + ALTER TABLE COPY algorithm RETURN Like mysql_alter_table(). */ -bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list) +bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy) { HA_CREATE_INFO create_info; Alter_info alter_info; @@ -9488,6 +9489,10 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list) /* Force alter table to recreate table */ alter_info.flags= (Alter_info::ALTER_CHANGE_COLUMN | Alter_info::ALTER_RECREATE); + + if (table_copy) + alter_info.requested_algorithm= Alter_info::ALTER_TABLE_ALGORITHM_COPY; + DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info, table_list, &alter_info, 0, (ORDER *) 0, 0)); diff --git a/sql/sql_table.h b/sql/sql_table.h index cd1c4293c39..444626e0363 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2006, 2013, Oracle and/or its affiliates. - Copyright (c) 2011, 2013, Monty Program Ab. +/* Copyright (c) 2006, 2014, Oracle and/or its affiliates. + Copyright (c) 2011, 2014, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -222,7 +222,7 @@ bool mysql_compare_tables(TABLE *table, Alter_info *alter_info, HA_CREATE_INFO *create_info, bool *metadata_equal); -bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list); +bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy); bool mysql_create_like_table(THD *thd, TABLE_LIST *table, TABLE_LIST *src_table, HA_CREATE_INFO *create_info); diff --git a/sql/sql_time.cc b/sql/sql_time.cc index 9b68aba5b30..c8a2c2daf85 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -1118,6 +1118,57 @@ int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b) } +/** + Convert TIME to DATETIME. + @param ltime The value to convert. + @return false on success, true of error (negative time). +*/ +bool time_to_datetime(MYSQL_TIME *ltime) +{ + DBUG_ASSERT(ltime->time_type == MYSQL_TIMESTAMP_TIME); + DBUG_ASSERT(ltime->year == 0); + DBUG_ASSERT(ltime->month == 0); + DBUG_ASSERT(ltime->day == 0); + if (ltime->neg) + return true; + uint day= ltime->hour / 24; + ltime->hour%= 24; + ltime->month= day / 31; + ltime->day= day % 31; + return false; +} + + +/** + Return a valid DATE or DATETIME value from an arbitrary MYSQL_TIME. + If ltime is TIME, it's first converted to DATETIME. + If ts_type is DATE, hhmmss is set to zero. + The date part of the result is checked against fuzzy_date. + + @param ltime The value to convert. + @param fuzzy_date Flags to check date. + @param ts_type The type to convert to. + @return false on success, true of error (negative time).*/ +bool +make_date_with_warn(MYSQL_TIME *ltime, ulonglong fuzzy_date, + timestamp_type ts_type) +{ + DBUG_ASSERT(ts_type == MYSQL_TIMESTAMP_DATE || + ts_type == MYSQL_TIMESTAMP_DATETIME); + if (ltime->time_type == MYSQL_TIMESTAMP_TIME && time_to_datetime(ltime)) + { + /* e.g. negative time */ + ErrConvTime str(ltime); + make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, + &str, ts_type, 0); + return true; + } + if ((ltime->time_type= ts_type) == MYSQL_TIMESTAMP_DATE) + ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; + return check_date_with_warn(ltime, fuzzy_date, ts_type); +} + + /* Convert a TIME value to DAY-TIME interval, e.g. for extraction: EXTRACT(DAY FROM x), EXTRACT(HOUR FROM x), etc. diff --git a/sql/sql_time.h b/sql/sql_time.h index 7513ca7c00a..5a468ef0649 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -33,6 +33,7 @@ typedef struct st_known_date_time_format KNOWN_DATE_TIME_FORMAT; ulong convert_period_to_month(ulong period); ulong convert_month_to_period(ulong month); +bool time_to_datetime(MYSQL_TIME *ltime); void time_to_daytime_interval(MYSQL_TIME *l_time); bool get_date_from_daynr(long daynr,uint *year, uint *month, uint *day); my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, uint *error_code); @@ -154,6 +155,8 @@ check_date(const MYSQL_TIME *ltime, ulonglong flags, int *was_cut) } bool check_date_with_warn(const MYSQL_TIME *ltime, ulonglong fuzzy_date, timestamp_type ts_type); +bool make_date_with_warn(MYSQL_TIME *ltime, + ulonglong fuzzy_date, timestamp_type ts_type); bool adjust_time_range_with_warn(MYSQL_TIME *ltime, uint dec); #endif /* SQL_TIME_INCLUDED */ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 395b4ef894b..70ac6265046 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -458,6 +458,13 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) */ thd->lex->sql_command= backup.sql_command; + if (opt_readonly && !(thd->security_ctx->master_access & SUPER_ACL) && + !thd->slave_thread) + { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); + goto end; + } + if (add_table_for_trigger(thd, thd->lex->spname, if_exists, & tables)) goto end; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 8ad3a2950d7..63e45ac1fec 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1425,11 +1425,11 @@ int mysql_multi_update_prepare(THD *thd) be write-locked (for example, trigger to be invoked might try to update this table). */ - tl->lock_type= read_lock_type_for_table(thd, lex, tl); + if (using_lock_tables) + tl->lock_type= read_lock_type_for_table(thd, lex, tl); + else + tl->set_lock_type(thd, read_lock_type_for_table(thd, lex, tl)); tl->updating= 0; - /* Update TABLE::lock_type accordingly. */ - if (!tl->placeholder() && !using_lock_tables) - tl->table->reginfo.lock_type= tl->lock_type; } } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 5da781f4bf5..d6b3fa41c78 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1,6 +1,6 @@ /* - Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2010, 2011, Monty Program Ab. + Copyright (c) 2000, 2014, Oracle and/or its affiliates. + Copyright (c) 2010, 2014, Monty Program Ab. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -442,6 +442,13 @@ set_system_variable(THD *thd, struct sys_var_with_base *tmp, if (lex->spcont && tmp->var == Sys_autocommit_ptr) lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT; + if (val && val->type() == Item::FIELD_ITEM && + ((Item_field*)val)->table_name) + { + my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), tmp->var->name.str); + return TRUE; + } + if (! (var= new set_var(var_type, tmp->var, &tmp->base_name, val))) return TRUE; @@ -14528,7 +14535,7 @@ opt_var_ident_type: | SESSION_SYM '.' { $$=OPT_SESSION; } ; -// Option values with preceeding option_type. +// Option values with preceding option_type. option_value_following_option_type: internal_variable_name equal set_expr_or_default { @@ -14544,7 +14551,7 @@ option_value_following_option_type: { /* Not in trigger assigning value to new row, - and option_type preceeding local variable is illegal. + and option_type preceding local variable is illegal. */ my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; @@ -14552,7 +14559,7 @@ option_value_following_option_type: } ; -// Option values without preceeding option_type. +// Option values without preceding option_type. option_value_no_option_type: internal_variable_name equal set_expr_or_default { diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 1807dc514ab..d9005f044bb 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -287,14 +287,15 @@ static Sys_var_long Sys_pfs_events_stages_history_size( - 1 for "statement/com/new_packet", for unknown enum_server_command - 1 for "statement/com/Error", for invalid enum_server_command - SQLCOM_END for all regular "statement/sql/...", - - 1 for "statement/sql/error", for invalid enum_sql_command. + - 1 for "statement/sql/error", for invalid enum_sql_command + - 1 for "statement/rpl/relay_log", for replicated statements. */ static Sys_var_ulong Sys_pfs_max_statement_classes( "performance_schema_max_statement_classes", "Maximum number of statement instruments.", PARSED_EARLY READ_ONLY GLOBAL_VAR(pfs_param.m_statement_class_sizing), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 256), - DEFAULT((ulong) SQLCOM_END + (ulong) COM_END + 3), + DEFAULT((ulong) SQLCOM_END + (ulong) COM_END + 4), BLOCK_SIZE(1)); static Sys_var_long Sys_pfs_events_statements_history_long_size( @@ -4663,7 +4664,7 @@ static Sys_var_mybool Sys_binlog_annotate_row_events( #ifdef HAVE_REPLICATION static Sys_var_mybool Sys_replicate_annotate_row_events( "replicate_annotate_row_events", - "Tells the slave to write annotate rows events recieved from the master " + "Tells the slave to write annotate rows events received from the master " "to its own binary log. Ignored if log_slave_updates is not set", READ_ONLY GLOBAL_VAR(opt_replicate_annotate_row_events), CMD_LINE(OPT_ARG), DEFAULT(0)); diff --git a/sql/table.cc b/sql/table.cc index 5da15dab9e7..bb336a0b9da 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4015,7 +4015,7 @@ void TABLE::init(THD *thd, TABLE_LIST *tl) status= STATUS_NO_RECORD; insert_values= 0; fulltext_searched= 0; - file->ha_start_of_new_statement(); + file->ft_handler= 0; reginfo.impossible_range= 0; created= TRUE; cond_selectivity= 1.0; @@ -7061,6 +7061,27 @@ bool TABLE_LIST::change_refs_to_fields() } +void TABLE_LIST::set_lock_type(THD *thd, enum thr_lock_type lock) +{ + if (check_stack_overrun(thd, STACK_MIN_SIZE, (uchar *)&lock)) + return; + /* we call it only when table is opened and it is "leaf" table*/ + DBUG_ASSERT(table); + lock_type= lock; + /* table->file->get_table() can be 0 for derived tables */ + if (table->file && table->file->get_table()) + table->file->set_lock_type(lock); + if (is_merged_derived()) + { + for (TABLE_LIST *table= get_single_select()->get_table_list(); + table; + table= table->next_local) + { + table->set_lock_type(thd, lock); + } + } +} + uint TABLE_SHARE::actual_n_key_parts(THD *thd) { return use_ext_keys && diff --git a/sql/table.h b/sql/table.h index f23e678697c..86e03cdaaf5 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2245,6 +2245,7 @@ struct TABLE_LIST } return false; } + void set_lock_type(THD* thd, enum thr_lock_type lock); private: bool prep_check_option(THD *thd, uint8 check_opt_type); diff --git a/sql/tztime.cc b/sql/tztime.cc index b0c5a0830fc..d3b4fec6335 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2033,7 +2033,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables) /* At last we are doing the same thing for records in - mysql.time_zone_transition table. Here we additionaly need records + mysql.time_zone_transition table. Here we additionally need records in ascending order by index scan also satisfies us. */ table= tz_tables->table; |