diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sp_head.cc | 7 | ||||
-rw-r--r-- | sql/sql_admin.cc | 45 | ||||
-rw-r--r-- | sql/sql_class.cc | 13 | ||||
-rw-r--r-- | sql/sql_class.h | 4 | ||||
-rw-r--r-- | sql/sql_error.cc | 23 | ||||
-rw-r--r-- | sql/sql_error.h | 28 | ||||
-rw-r--r-- | sql/sql_parse.cc | 16 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 7 | ||||
-rw-r--r-- | sql/sql_show.cc | 153 | ||||
-rw-r--r-- | sql/sql_trigger.cc | 25 |
10 files changed, 253 insertions, 68 deletions
diff --git a/sql/sp_head.cc b/sql/sp_head.cc index e87e03c1db7..3affee4058d 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1,4 +1,4 @@ -/* Copyright 2002-2008 MySQL AB, 2008-2010 Sun Microsystems, Inc. +/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -11,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" @@ -1217,7 +1217,8 @@ sp_head::execute(THD *thd, bool merge_da_on_success) String old_packet; Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer; Object_creation_ctx *saved_creation_ctx; - Warning_info *saved_warning_info, warning_info(thd->warning_info->warn_id()); + Warning_info *saved_warning_info; + Warning_info warning_info(thd->warning_info->warn_id(), false); /* Just reporting a stack overrun error diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index dea8d38938c..575991211e6 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -263,7 +263,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, const char *operator_name, thr_lock_type lock_type, bool open_for_modify, - bool no_warnings_for_error, + bool repair_table_use_frm, uint extra_open_options, int (*prepare_func)(THD *, TABLE_LIST *, HA_CHECK_OPT *), @@ -331,18 +331,43 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, lex->query_tables= table; lex->query_tables_last= &table->next_global; lex->query_tables_own_last= 0; - /* - Under locked tables, we know that the table can be opened, - so any errors opening the table are logical errors. - In these cases it makes sense to report them. - */ - if (!thd->locked_tables_mode) - thd->no_warnings_for_error= no_warnings_for_error; + if (view_operator_func == NULL) table->required_type=FRMTYPE_TABLE; - open_error= open_and_lock_tables(thd, table, TRUE, 0); - thd->no_warnings_for_error= 0; + if (!thd->locked_tables_mode && repair_table_use_frm) + { + /* + If we're not under LOCK TABLES and we're executing REPAIR TABLE + USE_FRM, we need to ignore errors from open_and_lock_tables(). + REPAIR TABLE USE_FRM is a heavy weapon used when a table is + critically damaged, so open_and_lock_tables() will most likely + report errors. Those errors are not interesting for the user + because it's already known that the table is badly damaged. + */ + + Warning_info wi(thd->query_id, false); + Warning_info *wi_saved= thd->warning_info; + + thd->warning_info= &wi; + + open_error= open_and_lock_tables(thd, table, TRUE, 0); + + thd->warning_info= wi_saved; + } + else + { + /* + It's assumed that even if it is REPAIR TABLE USE_FRM, the table + can be opened if we're under LOCK TABLES (otherwise LOCK TABLES + would fail). Thus, the only errors we could have from + open_and_lock_tables() are logical ones, like incorrect locking + mode. It does make sense for the user to see such errors. + */ + + open_error= open_and_lock_tables(thd, table, TRUE, 0); + } + table->next_global= save_next_global; table->next_local= save_next_local; thd->open_options&= ~extra_open_options; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index bc6086eaf19..a99a77c93a0 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -11,8 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /***************************************************************************** ** @@ -522,7 +521,7 @@ THD::THD() #if defined(ENABLED_DEBUG_SYNC) debug_sync_control(0), #endif /* defined(ENABLED_DEBUG_SYNC) */ - main_warning_info(0) + main_warning_info(0, false) { ulong tmp; @@ -581,7 +580,7 @@ THD::THD() client_capabilities= 0; // minimalistic client ull=0; system_thread= NON_SYSTEM_THREAD; - cleanup_done= abort_on_warning= no_warnings_for_error= 0; + cleanup_done= abort_on_warning= 0; peer_port= 0; // For SHOW PROCESSLIST transaction.m_pending_rows_event= 0; transaction.on= 1; @@ -854,10 +853,6 @@ MYSQL_ERROR* THD::raise_condition(uint sql_errno, query_cache_abort(&query_cache_tls); - /* FIXME: broken special case */ - if (no_warnings_for_error && (level == MYSQL_ERROR::WARN_LEVEL_ERROR)) - DBUG_RETURN(NULL); - /* When simulating OOM, skip writing to error log to avoid mtr errors */ DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_RETURN(NULL);); diff --git a/sql/sql_class.h b/sql/sql_class.h index 137a0c48ead..35c54b62a03 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2089,7 +2089,6 @@ public: bool enable_slow_log; /* enable slow log for current statement */ bool abort_on_warning; bool got_warning; /* Set on call to push_warning() */ - bool no_warnings_for_error; /* no warnings on call to my_error() */ /* set during loop of derived table processing */ bool derived_tables_processing; my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */ @@ -2807,6 +2806,7 @@ private: /** The current internal error handler for this thread, or NULL. */ Internal_error_handler *m_internal_handler; + /** The lex to hold the parsed tree of conventional (non-prepared) queries. Whereas for prepared and stored procedure statements we use an own lex diff --git a/sql/sql_error.cc b/sql/sql_error.cc index d0982b879e7..24516f03bee 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -1,5 +1,4 @@ -/* Copyright (C) 1995-2002 MySQL AB, - Copyright (C) 2008-2009 Sun Microsystems, Inc +/* Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -458,10 +457,11 @@ Diagnostics_area::disable_status() m_status= DA_DISABLED; } -Warning_info::Warning_info(ulonglong warn_id_arg) +Warning_info::Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings) :m_statement_warn_count(0), m_current_row_for_warning(1), m_warn_id(warn_id_arg), + m_allow_unlimited_warnings(allow_unlimited_warnings), m_read_only(FALSE) { /* Initialize sub structures */ @@ -543,7 +543,8 @@ MYSQL_ERROR *Warning_info::push_warning(THD *thd, if (! m_read_only) { - if (m_warn_list.elements < thd->variables.max_error_count) + if (m_allow_unlimited_warnings || + m_warn_list.elements < thd->variables.max_error_count) { cond= new (& m_warn_root) MYSQL_ERROR(& m_warn_root); if (cond) @@ -559,6 +560,20 @@ MYSQL_ERROR *Warning_info::push_warning(THD *thd, return cond; } +MYSQL_ERROR *Warning_info::push_warning(THD *thd, const MYSQL_ERROR *sql_condition) +{ + MYSQL_ERROR *new_condition= push_warning(thd, + sql_condition->get_sql_errno(), + sql_condition->get_sqlstate(), + sql_condition->get_level(), + sql_condition->get_message_text()); + + if (new_condition) + new_condition->copy_opt_attributes(sql_condition); + + return new_condition; +} + /* Push the warning to error list if there is still room in the list diff --git a/sql/sql_error.h b/sql/sql_error.h index 14dc5e6d12c..955b3767847 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -1,5 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB, - Copyright (C) 2008-2009 Sun Microsystems, Inc +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef SQL_ERROR_H #define SQL_ERROR_H @@ -323,10 +322,13 @@ class Warning_info { /** A memory root to allocate warnings and errors */ MEM_ROOT m_warn_root; + /** List of warnings of all severities (levels). */ List <MYSQL_ERROR> m_warn_list; + /** A break down of the number of warnings per severity (level). */ uint m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; + /** The number of warnings of the current statement. Warning_info life cycle differs from statement life cycle -- it may span @@ -334,20 +336,25 @@ class Warning_info m_statement_warn_count 0, whereas m_warn_list is not empty. */ uint m_statement_warn_count; + /* Row counter, to print in errors and warnings. Not increased in create_sort_index(); may differ from examined_row_count. */ ulong m_current_row_for_warning; - /** Used to optionally clear warnings only once per statement. */ + + /** Used to optionally clear warnings only once per statement. */ ulonglong m_warn_id; + /** Indicates if push_warning() allows unlimited number of warnings. */ + bool m_allow_unlimited_warnings; + private: Warning_info(const Warning_info &rhs); /* Not implemented */ Warning_info& operator=(const Warning_info &rhs); /* Not implemented */ public: - Warning_info(ulonglong warn_id_arg); + Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings); ~Warning_info(); /** @@ -384,19 +391,13 @@ public: void append_warnings(THD *thd, List<MYSQL_ERROR> *src) { MYSQL_ERROR *err; - MYSQL_ERROR *copy; List_iterator_fast<MYSQL_ERROR> it(*src); /* Don't use ::push_warning() to avoid invocation of condition handlers or escalation of warnings to errors. */ while ((err= it++)) - { - copy= Warning_info::push_warning(thd, err->get_sql_errno(), err->get_sqlstate(), - err->get_level(), err->get_message_text()); - if (copy) - copy->copy_opt_attributes(err); - } + Warning_info::push_warning(thd, err); } /** @@ -462,6 +463,9 @@ public: MYSQL_ERROR::enum_warning_level level, const char* msg); + /** Add a new condition to the current list. */ + MYSQL_ERROR *push_warning(THD *thd, const MYSQL_ERROR *sql_condition); + /** Set the read only status for this statement area. This is a privileged operation, reserved for the implementation of diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 367699ea6cb..d9d99de2911 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -7223,10 +7223,20 @@ bool parse_sql(THD *thd, bool mysql_parse_status= MYSQLparse(thd) != 0; - /* Check that if MYSQLparse() failed, thd->is_error() is set. */ + /* + Check that if MYSQLparse() failed either thd->is_error() is set, or an + internal error handler is set. + + The assert will not catch a situation where parsing fails without an + error reported if an error handler exists. The problem is that the + error handler might have intercepted the error, so thd->is_error() is + not set. However, there is no way to be 100% sure here (the error + handler might be for other errors than parsing one). + */ DBUG_ASSERT(!mysql_parse_status || - (mysql_parse_status && thd->is_error())); + (mysql_parse_status && thd->is_error()) || + (mysql_parse_status && thd->get_internal_handler())); /* Reset parser state. */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9085d018dfd..779569b10fb 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2842,7 +2842,8 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) param= stmt->param_array[param_number]; Diagnostics_area new_stmt_da, *save_stmt_da= thd->stmt_da; - Warning_info new_warnning_info(thd->query_id), *save_warinig_info= thd->warning_info; + Warning_info new_warnning_info(thd->query_id, false); + Warning_info *save_warinig_info= thd->warning_info; thd->stmt_da= &new_stmt_da; thd->warning_info= &new_warnning_info; @@ -3900,7 +3901,7 @@ Ed_result_set::Ed_result_set(List<Ed_row> *rows_arg, */ Ed_connection::Ed_connection(THD *thd) - :m_warning_info(thd->query_id), + :m_warning_info(thd->query_id, false), m_thd(thd), m_rsets(0), m_current_rset(0) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 464b966e4be..9e9de5e3524 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3416,6 +3416,45 @@ 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 +{ +public: + bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl) + { + if (sql_errno == ER_PARSE_ERROR || + sql_errno == ER_TRG_NO_DEFINER || + sql_errno == ER_TRG_NO_CREATION_CTX) + return true; + + return false; + } +}; + + + +/** @brief Fill I_S tables whose data are retrieved from frm files and storage engine @@ -3570,7 +3609,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0)) #endif { - thd->no_warnings_for_error= 1; List<LEX_STRING> table_names; int res= make_table_name_list(thd, &table_names, lex, &lookup_field_vals, @@ -3619,9 +3657,24 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) if (!(table_open_method & ~OPEN_FRM_ONLY) && !with_i_schema) { - if (!fill_schema_table_from_frm(thd, tables, schema_table, db_name, - table_name, schema_table_idx, - can_deadlock)) + /* + 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, + can_deadlock); + + thd->pop_internal_handler(); + + if (!res) continue; } @@ -3631,7 +3684,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) Set the parent lex of 'sel' because it is needed by sel.init_query() which is called inside make_table_list. */ - thd->no_warnings_for_error= 1; sel.parent_lex= lex; if (make_table_list(thd, &sel, db_name, table_name)) goto err; @@ -6675,6 +6727,92 @@ 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. + Warning_info wi(thd->query_id, true); + Warning_info *wi_saved= thd->warning_info; + + thd->warning_info= &wi; + + bool res= table_list->schema_table->fill_table( + thd, table_list, join_table->select_cond); + + thd->warning_info= wi_saved; + + // Pass an error if any. + + if (thd->stmt_da->is_error()) + { + thd->warning_info->push_warning(thd, + thd->stmt_da->sql_errno(), + thd->stmt_da->get_sqlstate(), + MYSQL_ERROR::WARN_LEVEL_ERROR, + thd->stmt_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(). + + + List_iterator_fast<MYSQL_ERROR> it(wi.warn_list()); + MYSQL_ERROR *err; + + while ((err= it++)) + { + if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_ERROR) + thd->warning_info->push_warning(thd, err); + } + + return res; +} + + /* Fill temporary schema tables before SELECT @@ -6697,7 +6835,6 @@ bool get_schema_tables_result(JOIN *join, bool result= 0; DBUG_ENTER("get_schema_tables_result"); - thd->no_warnings_for_error= 1; for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++) { if (!tab->table || !tab->table->pos_in_table_list) @@ -6748,8 +6885,7 @@ bool get_schema_tables_result(JOIN *join, else table_list->table->file->stats.records= 0; - if (table_list->schema_table->fill_table(thd, table_list, - tab->select_cond)) + if (do_fill_table(thd, table_list, tab)) { result= 1; join->error= 1; @@ -6761,7 +6897,6 @@ bool get_schema_tables_result(JOIN *join, table_list->schema_table_state= executed_place; } } - thd->no_warnings_for_error= 0; DBUG_RETURN(result); } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 4908fce5950..d026714c007 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -1225,13 +1225,12 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, DBUG_RETURN(1); // EOM } - - if (!thd->no_warnings_for_error) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRG_NO_CREATION_CTX, - ER(ER_TRG_NO_CREATION_CTX), - (const char*) db, - (const char*) table_name); + + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRG_NO_CREATION_CTX, + ER(ER_TRG_NO_CREATION_CTX), + (const char*) db, + (const char*) table_name); if (!(trg_client_cs_name= alloc_lex_string(&table->mem_root)) || !(trg_connection_cl_name= alloc_lex_string(&table->mem_root)) || @@ -1362,12 +1361,12 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, MySQL, which does not support triggers definers. We should emit warning here. */ - if (!thd->no_warnings_for_error) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER), - (const char*) db, - (const char*) sp->m_name.str); - + + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER), + (const char*) db, + (const char*) sp->m_name.str); + /* Set definer to the '' to correct displaying in the information schema. |