mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 04:22:27 +01:00
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
This commit is contained in:
commit
0708859ba8
12 changed files with 259 additions and 31 deletions
|
@ -98,13 +98,13 @@ where table_schema='test';
|
|||
table_name table_type table_comment
|
||||
t1 BASE TABLE
|
||||
v1 VIEW VIEW
|
||||
v2 VIEW View 'test.v2' references invalid table(s) or column(s) or function(s) or define
|
||||
v2 VIEW VIEW
|
||||
drop table t1;
|
||||
select table_name, table_type, table_comment from information_schema.tables
|
||||
where table_schema='test';
|
||||
table_name table_type table_comment
|
||||
v1 VIEW View 'test.v1' references invalid table(s) or column(s) or function(s) or define
|
||||
v2 VIEW View 'test.v2' references invalid table(s) or column(s) or function(s) or define
|
||||
v1 VIEW VIEW
|
||||
v2 VIEW VIEW
|
||||
drop function f1;
|
||||
drop function f2;
|
||||
drop view v1, v2;
|
||||
|
|
|
@ -1935,11 +1935,11 @@ create function f1 () returns int return (select max(col1) from t1);
|
|||
DROP TABLE t1;
|
||||
CHECK TABLE v1, v2, v3, v4, v5, v6;
|
||||
Table Op Msg_type Msg_text
|
||||
test.v1 check error View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
test.v1 check status OK
|
||||
test.v2 check status OK
|
||||
test.v3 check error View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
test.v3 check status OK
|
||||
test.v4 check status OK
|
||||
test.v5 check error View 'test.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
test.v5 check status OK
|
||||
test.v6 check status OK
|
||||
drop function f1;
|
||||
drop function f2;
|
||||
|
|
|
@ -1369,7 +1369,7 @@ end|
|
|||
select f11()|
|
||||
--error ER_CANT_REOPEN_TABLE
|
||||
select f11() from t1|
|
||||
# We don't handle temporary tables used by nested functions well
|
||||
# Test that using a single table instance at a time works
|
||||
create function f12_1() returns int
|
||||
begin
|
||||
drop temporary table if exists t3;
|
||||
|
@ -1379,11 +1379,9 @@ begin
|
|||
end|
|
||||
create function f12_2() returns int
|
||||
return (select count(*) from t3)|
|
||||
# We need clean start to get error
|
||||
|
||||
drop temporary table t3|
|
||||
--error ER_NO_SUCH_TABLE
|
||||
select f12_1()|
|
||||
--error ER_NO_SUCH_TABLE
|
||||
select f12_1() from t1 limit 1|
|
||||
|
||||
# Cleanup
|
||||
|
@ -6802,6 +6800,53 @@ CALL bug24117()|
|
|||
DROP PROCEDURE bug24117|
|
||||
DROP TABLE t3|
|
||||
|
||||
#
|
||||
# Bug#8407(Stored functions/triggers ignore exception handler)
|
||||
#
|
||||
|
||||
--disable_warnings
|
||||
drop function if exists func_8407_a|
|
||||
drop function if exists func_8407_b|
|
||||
--enable_warnings
|
||||
|
||||
create function func_8407_a() returns int
|
||||
begin
|
||||
declare x int;
|
||||
|
||||
declare continue handler for sqlexception
|
||||
begin
|
||||
end;
|
||||
|
||||
select 1 from no_such_view limit 1 into x;
|
||||
|
||||
return x;
|
||||
end|
|
||||
|
||||
create function func_8407_b() returns int
|
||||
begin
|
||||
declare x int default 0;
|
||||
|
||||
declare continue handler for sqlstate '42S02'
|
||||
begin
|
||||
set x:= x+1000;
|
||||
end;
|
||||
|
||||
case (select 1 from no_such_view limit 1)
|
||||
when 1 then set x:= x+1;
|
||||
when 2 then set x:= x+2;
|
||||
else set x:= x+100;
|
||||
end case;
|
||||
set x:=x + 500;
|
||||
|
||||
return x;
|
||||
end|
|
||||
|
||||
select func_8407_a()|
|
||||
select func_8407_b()|
|
||||
|
||||
drop function func_8407_a|
|
||||
drop function func_8407_b|
|
||||
|
||||
#
|
||||
# NOTE: The delimiter is `|`, and not `;`. It is changed to `;`
|
||||
# at the end of the file!
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
102
sql/sql_base.cc
102
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue