diff options
author | Davi Arnaut <Davi.Arnaut@Sun.COM> | 2010-03-10 10:36:40 -0300 |
---|---|---|
committer | Davi Arnaut <Davi.Arnaut@Sun.COM> | 2010-03-10 10:36:40 -0300 |
commit | 30cb1779ed3c2666bf72ab6d068025cf06963ff3 (patch) | |
tree | 63a59799aa68a830ed65ed4c3589abbcd1580e75 /sql/lock.cc | |
parent | 9661d1ef34ce7ec8e24895ef998409fdcdd10edf (diff) | |
download | mariadb-git-30cb1779ed3c2666bf72ab6d068025cf06963ff3.tar.gz |
Bug#33669: Transactional temporary tables do not work under --read-only
The problem was that in read only mode (read_only enabled),
the server would mistakenly deny data modification attempts
for temporary tables which belong to a transactional storage
engine (eg. InnoDB).
The solution is to allow transactional temporary tables to be
modified under read only mode. As a whole, the read only mode
does not apply to any kind of temporary table.
Diffstat (limited to 'sql/lock.cc')
-rw-r--r-- | sql/lock.cc | 105 |
1 files changed, 46 insertions, 59 deletions
diff --git a/sql/lock.cc b/sql/lock.cc index 3ff131bb828..78a16cea18a 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -89,8 +89,8 @@ extern HASH open_cache; #define GET_LOCK_UNLOCK 1 #define GET_LOCK_STORE_LOCKS 2 -static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count, - uint flags, TABLE **write_locked); +static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, + uint flags); static int lock_external(THD *thd, TABLE **table,uint count); static int unlock_external(THD *thd, TABLE **table,uint count); static void print_lock_error(int error, const char *); @@ -107,15 +107,18 @@ static int thr_lock_errno_to_mysql[]= @param flags Lock flags @return 0 if all the check passed, non zero if a check failed. */ -int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags) +static int +lock_tables_check(THD *thd, TABLE **tables, uint count, + bool *write_lock_used, uint flags) { - bool log_table_write_query; - uint system_count; - uint i; + uint system_count, i; + bool is_superuser, log_table_write_query; - DBUG_ENTER("mysql_lock_tables_check"); + DBUG_ENTER("lock_tables_check"); system_count= 0; + *write_lock_used= FALSE; + is_superuser= thd->security_ctx->master_access & SUPER_ACL; log_table_write_query= (is_log_table_write_query(thd->lex->sql_command) || ((flags & MYSQL_LOCK_PERF_SCHEMA) != 0)); @@ -148,10 +151,18 @@ int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags) } } - if ((t->s->table_category == TABLE_CATEGORY_SYSTEM) && - (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE)) + if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE) { - system_count++; + *write_lock_used= TRUE; + + if (t->s->table_category == TABLE_CATEGORY_SYSTEM) + system_count++; + + if (t->db_stat & HA_READ_ONLY) + { + my_error(ER_OPEN_AS_READONLY, MYF(0), t->alias); + DBUG_RETURN(1); + } } /* @@ -172,6 +183,20 @@ int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags) thd->mdl_context.is_lock_owner(MDL_key::TABLE, t->s->db.str, t->s->table_name.str, MDL_SHARED))); + + /* + Prevent modifications to base tables if READ_ONLY is activated. + In any case, read only does not apply to temporary tables. + */ + if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) && !t->s->tmp_table) + { + if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE && + !is_superuser && opt_readonly && !thd->slave_thread) + { + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); + DBUG_RETURN(1); + } + } } /* @@ -267,15 +292,15 @@ static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock) MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags, bool *need_reopen) { - MYSQL_LOCK *sql_lock; - TABLE *write_lock_used; int rc; + MYSQL_LOCK *sql_lock; + bool write_lock_used; DBUG_ENTER("mysql_lock_tables"); *need_reopen= FALSE; - if (mysql_lock_tables_check(thd, tables, count, flags)) + if (lock_tables_check(thd, tables, count, &write_lock_used, flags)) DBUG_RETURN (NULL); ulong timeout= (flags & MYSQL_LOCK_IGNORE_TIMEOUT) ? @@ -283,8 +308,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, for (;;) { - if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS, - &write_lock_used))) + if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS))) break; if (global_read_lock && write_lock_used && @@ -308,21 +332,6 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, } } - if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) && - write_lock_used && - opt_readonly && - !(thd->security_ctx->master_access & SUPER_ACL) && - !thd->slave_thread) - { - /* - Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock. - We do not wait for READ_ONLY=0, and fail. - */ - reset_lock_data_and_free(&sql_lock); - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); - break; - } - thd_proc_info(thd, "System lock"); DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info)); if (sql_lock->table_count && lock_external(thd, sql_lock->table, @@ -459,9 +468,7 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock) void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count) { MYSQL_LOCK *sql_lock; - TABLE *write_lock_used; - if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK, - &write_lock_used))) + if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK))) mysql_unlock_tables(thd, sql_lock); } @@ -603,9 +610,7 @@ void mysql_lock_downgrade_write(THD *thd, TABLE *table, thr_lock_type new_lock_type) { MYSQL_LOCK *locked; - TABLE *write_lock_used; - if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK, - &write_lock_used))) + if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK))) { for (uint i=0; i < locked->lock_count; i++) thr_downgrade_write_lock(locked->locks[i], new_lock_type); @@ -619,11 +624,9 @@ void mysql_lock_downgrade_write(THD *thd, TABLE *table, void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock) { MYSQL_LOCK *locked; - TABLE *write_lock_used; DBUG_ENTER("mysql_lock_abort"); - if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK, - &write_lock_used))) + if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK))) { for (uint i=0; i < locked->lock_count; i++) thr_abort_locks(locked->locks[i]->lock, upgrade_lock); @@ -648,12 +651,10 @@ void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock) bool mysql_lock_abort_for_thread(THD *thd, TABLE *table) { MYSQL_LOCK *locked; - TABLE *write_lock_used; bool result= FALSE; DBUG_ENTER("mysql_lock_abort_for_thread"); - if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK, - &write_lock_used))) + if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK))) { for (uint i=0; i < locked->lock_count; i++) { @@ -848,11 +849,10 @@ static int unlock_external(THD *thd, TABLE **table,uint count) @param flags One of: - GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock - GET_LOCK_STORE_LOCKS : Store lock info in TABLE - @param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE */ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, - uint flags, TABLE **write_lock_used) + uint flags) { uint i,tables,lock_count; MYSQL_LOCK *sql_lock; @@ -861,9 +861,8 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, DBUG_ENTER("get_lock_data"); DBUG_ASSERT((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS)); - DBUG_PRINT("info", ("count %d", count)); - *write_lock_used=0; + for (i=tables=lock_count=0 ; i < count ; i++) { TABLE *t= table_ptr[i]; @@ -895,24 +894,12 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, { TABLE *table; enum thr_lock_type lock_type; + THR_LOCK_DATA **org_locks = locks; if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE) continue; lock_type= table->reginfo.lock_type; DBUG_ASSERT(lock_type != TL_WRITE_DEFAULT && lock_type != TL_READ_DEFAULT); - if (lock_type >= TL_WRITE_ALLOW_WRITE) - { - *write_lock_used=table; - if (table->db_stat & HA_READ_ONLY) - { - my_error(ER_OPEN_AS_READONLY,MYF(0),table->alias); - /* Clear the lock type of the lock data that are stored already. */ - sql_lock->lock_count= (uint) (locks - sql_lock->locks); - reset_lock_data_and_free(&sql_lock); - DBUG_RETURN(0); - } - } - THR_LOCK_DATA **org_locks = locks; locks_start= locks; locks= table->file->store_lock(thd, locks, (flags & GET_LOCK_UNLOCK) ? TL_IGNORE : |