summaryrefslogtreecommitdiff
path: root/sql/lock.cc
diff options
context:
space:
mode:
authorDavi Arnaut <Davi.Arnaut@Sun.COM>2010-03-10 10:36:40 -0300
committerDavi Arnaut <Davi.Arnaut@Sun.COM>2010-03-10 10:36:40 -0300
commit30cb1779ed3c2666bf72ab6d068025cf06963ff3 (patch)
tree63a59799aa68a830ed65ed4c3589abbcd1580e75 /sql/lock.cc
parent9661d1ef34ce7ec8e24895ef998409fdcdd10edf (diff)
downloadmariadb-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.cc105
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 :