diff options
author | unknown <malff/marcsql@weblab.(none)> | 2007-03-06 10:33:10 -0700 |
---|---|---|
committer | unknown <malff/marcsql@weblab.(none)> | 2007-03-06 10:33:10 -0700 |
commit | 0708859ba8a7490cf3f4ba73c667105d2a6edbd7 (patch) | |
tree | 89e46d1e53cc7db75cbfc56e2cadc40161bebc1e /sql | |
parent | c155c66da65e3d19b2baec7d141648dfd9b55f52 (diff) | |
parent | 266a7fff520eb2253226158df236865f2ad16ffe (diff) | |
download | mariadb-git-0708859ba8a7490cf3f4ba73c667105d2a6edbd7.tar.gz |
Merge weblab.(none):/home/marcsql/TREE/mysql-5.0-8407_b
into weblab.(none):/home/marcsql/TREE/mysql-5.1-8407-merge
mysql-test/r/information_schema_db.result:
Auto merged
mysql-test/r/view.result:
Auto merged
mysql-test/t/sp.test:
Auto merged
sql/lock.cc:
Auto merged
sql/mysqld.cc:
Auto merged
sql/sp_head.cc:
Auto merged
sql/sp_head.h:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_class.cc:
Auto merged
sql/sql_update.cc:
Auto merged
sql/table.cc:
Auto merged
sql/table.h:
Auto merged
Diffstat (limited to 'sql')
-rw-r--r-- | sql/lock.cc | 2 | ||||
-rw-r--r-- | sql/mysqld.cc | 8 | ||||
-rw-r--r-- | sql/sp_head.cc | 49 | ||||
-rw-r--r-- | sql/sp_head.h | 24 | ||||
-rw-r--r-- | sql/sql_base.cc | 102 | ||||
-rw-r--r-- | sql/sql_class.cc | 32 | ||||
-rw-r--r-- | sql/sql_update.cc | 2 | ||||
-rw-r--r-- | sql/table.cc | 4 | ||||
-rw-r--r-- | sql/table.h | 2 |
9 files changed, 204 insertions, 21 deletions
diff --git a/sql/lock.cc b/sql/lock.cc index edef3b3b67f..a93033bfdd0 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -604,7 +604,7 @@ TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle, for (; haystack; haystack= haystack->next_global) { - if (haystack->placeholder() || haystack->schema_table) + if (haystack->placeholder()) continue; table2= haystack->table; if (table2->s->tmp_table == TMP_TABLE) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 425088f622c..8a6d00e44a1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2553,6 +2553,14 @@ static int my_message_sql(uint error, const char *str, myf MyFlags) */ if ((thd= current_thd)) { + /* + TODO: There are two exceptions mechanism (THD and sp_rcontext), + this could be improved by having a common stack of handlers. + */ + if (thd->handle_error(error, + MYSQL_ERROR::WARN_LEVEL_ERROR)) + DBUG_RETURN(0); + if (thd->spcont && thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd)) { diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 20d45af7415..1e0986f6e82 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2444,16 +2444,11 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, m_lex->mark_as_requiring_prelocking(lex_query_tables_own_last); } } - + reinit_stmt_before_use(thd, m_lex); - /* - If requested check whenever we have access to tables in LEX's table list - and open and lock them before executing instructtions core function. - */ - if (open_tables && - (check_table_access(thd, SELECT_ACL, m_lex->query_tables, 0) || - open_and_lock_tables(thd, m_lex->query_tables))) - res= -1; + + if (open_tables) + res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables, nextp); if (!res) { @@ -2505,6 +2500,33 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, sp_instr class functions */ +int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables, + uint *nextp) +{ + int result; + + /* + Check whenever we have access to tables for this statement + and open and lock them before executing instructions core function. + */ + if (check_table_access(thd, SELECT_ACL, tables, 0) + || open_and_lock_tables(thd, tables)) + { + get_cont_dest(nextp); + result= -1; + } + else + result= 0; + + return result; +} + +void sp_instr::get_cont_dest(uint *nextp) +{ + *nextp= m_ip+1; +} + + int sp_instr::exec_core(THD *thd, uint *nextp) { DBUG_ASSERT(0); @@ -2690,6 +2712,15 @@ sp_instr_set_trigger_field::print(String *str) value->print(str); } +/* + sp_instr_opt_meta +*/ + +void sp_instr_opt_meta::get_cont_dest(uint *nextp) +{ + *nextp= m_cont_dest; +} + /* sp_instr_jump class functions diff --git a/sql/sp_head.h b/sql/sp_head.h index be6eefa2ea4..46ad3dd96d8 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -477,6 +477,28 @@ public: virtual int execute(THD *thd, uint *nextp) = 0; + /** + Execute <code>open_and_lock_tables()</code> for this statement. + Open and lock the tables used by this statement, as a pre-requisite + to execute the core logic of this instruction with + <code>exec_core()</code>. + If this statement fails, the next instruction to execute is also returned. + This is useful when a user defined SQL continue handler needs to be + executed. + @param thd the current thread + @param tables the list of tables to open and lock + @param nextp the continuation instruction, returned to the caller if this + method fails. + @return zero on success, non zero on failure. + */ + int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables, uint *nextp); + + /** + Get the continuation destination of this instruction. + @param nextp the continuation destination (output) + */ + virtual void get_cont_dest(uint *nextp); + /* Execute core function of instruction after all preparations (e.g. setting of proper LEX, saving part of the thread context have been @@ -741,6 +763,8 @@ public: virtual void set_destination(uint old_dest, uint new_dest) = 0; + virtual void get_cont_dest(uint *nextp); + protected: sp_instr *m_optdest; // Used during optimization diff --git a/sql/sql_base.cc b/sql/sql_base.cc index ac1222e6bd6..6d831952df5 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -28,6 +28,59 @@ #include <io.h> #endif +/** + This internal handler is used to trap internally + errors that can occur when executing open table + during the prelocking phase. +*/ +class Prelock_error_handler : public Internal_error_handler +{ +public: + Prelock_error_handler() + : m_handled_errors(0), m_unhandled_errors(0) + {} + + virtual ~Prelock_error_handler() {} + + virtual bool handle_error(uint sql_errno, + MYSQL_ERROR::enum_warning_level level, + THD *thd); + + bool safely_trapped_errors(); + +private: + int m_handled_errors; + int m_unhandled_errors; +}; + + +bool +Prelock_error_handler::handle_error(uint sql_errno, + MYSQL_ERROR::enum_warning_level /* level */, + THD * /* thd */) +{ + if (sql_errno == ER_NO_SUCH_TABLE) + { + m_handled_errors++; + return TRUE; // 'TRUE', as per coding style + } + + m_unhandled_errors++; + return FALSE; // 'FALSE', as per coding style +} + + +bool Prelock_error_handler::safely_trapped_errors() +{ + /* + If m_unhandled_errors != 0, something else, unanticipated, happened, + so the error is not trapped but returned to the caller. + Multiple ER_NO_SUCH_TABLE can be raised in case of views. + */ + return ((m_handled_errors > 0) && (m_unhandled_errors == 0)); +} + + TABLE *unused_tables; /* Used by mysql_test */ HASH open_cache; /* Used by mysql_test */ static HASH table_def_cache; @@ -1977,7 +2030,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, VOID(pthread_mutex_unlock(&LOCK_open)); } } - my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias); + if ((thd->locked_tables) && (thd->locked_tables->lock_count > 0)) + my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias); + else + my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias); DBUG_RETURN(0); } @@ -2860,6 +2916,8 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) MEM_ROOT new_frm_mem; /* Also used for indicating that prelocking is need */ TABLE_LIST **query_tables_last_own; + bool safe_to_ignore_table; + DBUG_ENTER("open_tables"); /* temporary mem_root for new .frm parsing. @@ -2908,6 +2966,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) for (tables= *start; tables ;tables= tables->next_global) { + safe_to_ignore_table= FALSE; // 'FALSE', as per coding style /* Ignore placeholders for derived tables. After derived tables processing, link to created temporary table will be put here. @@ -2927,9 +2986,28 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) DBUG_RETURN(-1); } (*counter)++; - - if (!tables->table && - !(tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags))) + + if (!tables->table) + { + if (tables->prelocking_placeholder) + { + /* + For the tables added by the pre-locking code, attempt to open + the table but fail silently if the table does not exist. + The real failure will occur when/if a statement attempts to use + that table. + */ + Prelock_error_handler prelock_handler; + thd->push_internal_handler(& prelock_handler); + tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags); + thd->pop_internal_handler(); + safe_to_ignore_table= prelock_handler.safely_trapped_errors(); + } + else + tables->table= open_table(thd, tables, &new_frm_mem, &refresh, flags); + } + + if (!tables->table) { free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC)); @@ -2980,6 +3058,14 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) close_tables_for_reopen(thd, start); goto restart; } + + if (safe_to_ignore_table) + { + DBUG_PRINT("info", ("open_table: ignoring table '%s'.'%s'", + tables->db, tables->alias)); + continue; + } + result= -1; // Fatal error break; } @@ -3283,7 +3369,7 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags) static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table) { for (; table; table= table->next_global) - if (!table->placeholder() && !table->schema_table) + if (!table->placeholder()) table->table->query_id= 0; } @@ -3356,7 +3442,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) DBUG_RETURN(-1); for (table= tables; table; table= table->next_global) { - if (!table->placeholder() && !table->schema_table) + if (!table->placeholder()) *(ptr++)= table->table; } @@ -3409,7 +3495,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) for (table= tables; table != first_not_own; table= table->next_global) { - if (!table->placeholder() && !table->schema_table) + if (!table->placeholder()) { table->table->query_id= thd->query_id; if (check_lock_and_start_stmt(thd, table->table, table->lock_type)) @@ -3436,7 +3522,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) TABLE_LIST *first_not_own= thd->lex->first_not_own_table(); for (table= tables; table != first_not_own; table= table->next_global) { - if (!table->placeholder() && !table->schema_table && + if (!table->placeholder() && check_lock_and_start_stmt(thd, table->table, table->lock_type)) { ha_rollback_stmt(thd); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 6673ed1ddf0..cdb75e763b6 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -309,6 +309,38 @@ THD::THD() substitute_null_with_insert_id = FALSE; thr_lock_info_init(&lock_info); /* safety: will be reset after start */ thr_lock_owner_init(&main_lock_id, &lock_info); + + m_internal_handler= NULL; +} + + +void THD::push_internal_handler(Internal_error_handler *handler) +{ + /* + TODO: The current implementation is limited to 1 handler at a time only. + THD and sp_rcontext need to be modified to use a common handler stack. + */ + DBUG_ASSERT(m_internal_handler == NULL); + m_internal_handler= handler; +} + + +bool THD::handle_error(uint sql_errno, + MYSQL_ERROR::enum_warning_level level) +{ + if (m_internal_handler) + { + return m_internal_handler->handle_error(sql_errno, level, this); + } + + return FALSE; // 'FALSE', as per coding style +} + + +void THD::pop_internal_handler() +{ + DBUG_ASSERT(m_internal_handler != NULL); + m_internal_handler= NULL; } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 02a90b942bf..27a58a295ff 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -907,7 +907,7 @@ reopen_tables: tl->lock_type= using_update_log ? TL_READ_NO_INSERT : TL_READ; tl->updating= 0; /* Update TABLE::lock_type accordingly. */ - if (!tl->placeholder() && !tl->schema_table && !using_lock_tables) + if (!tl->placeholder() && !using_lock_tables) tl->table->reginfo.lock_type= tl->lock_type; } } diff --git a/sql/table.cc b/sql/table.cc index 0fe1f37e9b1..560f53bae26 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2890,7 +2890,9 @@ void st_table_list::hide_view_error(THD *thd) thd->net.last_errno == ER_SP_DOES_NOT_EXIST || thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR || thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR || - thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR) + thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR || + thd->net.last_errno == ER_TABLE_NOT_LOCKED || + thd->net.last_errno == ER_NO_SUCH_TABLE) { TABLE_LIST *top= top_table(); thd->clear_error(); diff --git a/sql/table.h b/sql/table.h index b055bfb74e6..54c820d391c 100644 --- a/sql/table.h +++ b/sql/table.h @@ -856,7 +856,7 @@ typedef struct st_table_list int view_check_option(THD *thd, bool ignore_failure); bool setup_underlying(THD *thd); void cleanup_items(); - bool placeholder() {return derived || view; } + bool placeholder() {return derived || view || schema_table || !table; } void print(THD *thd, String *str); bool check_single_table(st_table_list **table, table_map map, st_table_list *view); |