diff options
author | Sergei Golubchik <sergii@pisem.net> | 2014-05-09 12:35:11 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2014-05-09 12:35:11 +0200 |
commit | d3e2e1243bb0dae95ce35b0380dd4f8f476b254d (patch) | |
tree | 8779ad6b2059f181770cc07e2437925d7d5d5d04 /sql | |
parent | 229dad1f9b12f8e9f64b6a605bdf8e31c339d018 (diff) | |
parent | 124428a9e28e59f98b25d8ee07b57d264f63cbe4 (diff) | |
download | mariadb-git-d3e2e1243bb0dae95ce35b0380dd4f8f476b254d.tar.gz |
5.5 merge
Diffstat (limited to 'sql')
57 files changed, 482 insertions, 271 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index ad4b12813d3..0665323285a 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/handler.cc b/sql/handler.cc index 2991b6eb11c..ac2512431ad 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3889,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 @@ -6115,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 d67d7fb0888..49e18facdb7 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2471,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 @@ -2552,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), @@ -2633,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() { @@ -3738,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; @@ -3949,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/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..e6a903e2485 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -6250,16 +6250,38 @@ 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; } + /* + 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(((Item_field *)item)->field->table); } @@ -6277,15 +6299,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/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 b68d6c1fbc3..f5dfbe221aa 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 @@ -9445,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, @@ -9766,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 @@ -11098,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; } @@ -11109,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) || @@ -11261,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..020af59ae81 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 @@ -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 a9ee5890fdf..d86a1743468 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 @@ -2237,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); @@ -9342,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}; @@ -9370,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}; @@ -9394,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}; @@ -9462,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, @@ -9493,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, @@ -9517,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, diff --git a/sql/mysqld.h b/sql/mysqld.h index 09f886bff01..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; @@ -623,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/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/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/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_admin.cc b/sql/sql_admin.cc index b3f53e3457a..34a076cc327 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -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))) 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_parse.cc b/sql/sql_parse.cc index ac23880de8a..922f0d73165 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -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_select.cc b/sql/sql_select.cc index 7d69a85a273..b97cedb5b05 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); 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_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..9ea72676b13 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; 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); |