81 #include "sql_parse.h"
91 extern HASH open_cache;
94 #define GET_LOCK_UNLOCK 1
95 #define GET_LOCK_STORE_LOCKS 2
97 static MYSQL_LOCK *get_lock_data(THD *thd,
TABLE **table_ptr, uint count,
99 static int lock_external(THD *thd,
TABLE **
table,uint count);
100 static int unlock_external(THD *thd,
TABLE **
table,uint count);
101 static void print_lock_error(
int error,
const char *);
104 static int thr_lock_errno_to_mysql[]=
105 { 0, ER_LOCK_ABORTED, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
116 lock_tables_check(THD *thd,
TABLE **tables, uint count, uint
flags)
118 uint system_count= 0,
i= 0;
119 bool is_superuser=
false;
124 bool log_table_write_query=
false;
126 DBUG_ENTER(
"lock_tables_check");
128 is_superuser= thd->security_ctx->master_access & SUPER_ACL;
129 log_table_write_query=
132 for (
i=0 ;
i<count;
i++)
146 (flags & MYSQL_LOCK_LOG_TABLE) == 0 &&
147 !log_table_write_query)
154 if (t->reginfo.lock_type >= TL_READ_NO_INSERT ||
155 thd->lex->sql_command == SQLCOM_LOCK_TABLES)
157 my_error(ER_CANT_LOCK_LOG_TABLE, MYF(0));
162 if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE)
167 if (t->db_stat & HA_READ_ONLY)
169 my_error(ER_OPEN_AS_READONLY, MYF(0), t->alias);
183 DBUG_ASSERT(t->s->tmp_table ||
184 thd->mdl_context.is_lock_owner(MDL_key::TABLE,
185 t->s->db.str, t->s->table_name.str,
186 t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE ?
187 MDL_SHARED_WRITE : MDL_SHARED_READ) ||
188 (t->open_by_handler &&
189 thd->mdl_context.is_lock_owner(MDL_key::TABLE,
190 t->s->db.str, t->s->table_name.str,
197 if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) && !t->s->tmp_table)
199 if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE &&
200 !is_superuser && opt_readonly && !thd->slave_thread)
202 my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
"--read-only");
213 if ((system_count > 0) && (system_count < count))
215 my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0));
243 static void reset_lock_data(
MYSQL_LOCK *sql_lock)
246 DBUG_ENTER(
"reset_lock_data");
249 for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count;
254 (*ldata)->type= TL_UNLOCK;
267 static void reset_lock_data_and_free(
MYSQL_LOCK **mysql_lock)
269 reset_lock_data(*mysql_lock);
270 my_free(*mysql_lock);
293 ulong timeout= (flags & MYSQL_LOCK_IGNORE_TIMEOUT) ?
294 LONG_TIMEOUT : thd->variables.lock_wait_timeout;
296 DBUG_ENTER(
"mysql_lock_tables");
298 if (lock_tables_check(thd, tables, count, flags))
301 if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS)))
304 THD_STAGE_INFO(thd, stage_system_lock);
305 DBUG_PRINT(
"info", (
"thd->proc_info %s", thd->proc_info));
306 if (sql_lock->table_count && lock_external(thd, sql_lock->table,
307 sql_lock->table_count))
310 reset_lock_data_and_free(&sql_lock);
315 memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
316 sql_lock->lock_count *
sizeof(*sql_lock->locks));
318 rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
319 sql_lock->lock_count,
320 sql_lock->lock_count,
321 &thd->lock_info, timeout)];
324 if (sql_lock->table_count)
325 (void) unlock_external(thd, sql_lock->table, sql_lock->table_count);
326 reset_lock_data_and_free(&sql_lock);
328 my_error(rc, MYF(0));
331 if (!(flags & MYSQL_OPEN_IGNORE_KILLED) && thd->killed)
333 thd->send_kill_message();
336 mysql_unlock_tables(thd, sql_lock);
341 thd->set_time_after_lock();
342 DBUG_RETURN(sql_lock);
346 static int lock_external(THD *thd,
TABLE **tables, uint count)
350 DBUG_ENTER(
"lock_external");
352 DBUG_PRINT(
"info", (
"count %d", count));
353 for (i=1 ; i <= count ; i++, tables++)
355 DBUG_ASSERT((*tables)->reginfo.lock_type >= TL_READ);
357 if ((*tables)->db_stat & HA_READ_ONLY ||
358 ((*tables)->reginfo.lock_type >= TL_READ &&
359 (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
362 if ((error=(*tables)->file->ha_external_lock(thd,lock_type)))
364 print_lock_error(error, (*tables)->file->table_type());
369 (*tables)->current_lock=F_UNLCK;
375 (*tables)->db_stat &= ~ HA_BLOCK_LOCK;
376 (*tables)->current_lock= lock_type;
383 void mysql_unlock_tables(THD *thd,
MYSQL_LOCK *sql_lock)
385 DBUG_ENTER(
"mysql_unlock_tables");
386 if (sql_lock->lock_count)
387 thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
388 if (sql_lock->table_count)
389 (void) unlock_external(thd,sql_lock->table,sql_lock->table_count);
403 if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK)))
404 mysql_unlock_tables(thd, sql_lock);
415 DBUG_ENTER(
"mysql_unlock_read_tables");
419 for (i=found=0 ; i < sql_lock->lock_count ; i++)
421 if (sql_lock->locks[i]->type > TL_WRITE_ALLOW_WRITE)
431 thr_multi_unlock(lock,i-found);
432 sql_lock->lock_count= found;
438 for (i=found=0 ; i < sql_lock->table_count ; i++)
440 DBUG_ASSERT(sql_lock->table[i]->lock_position == i);
441 if ((uint) sql_lock->table[i]->reginfo.lock_type > TL_WRITE_ALLOW_WRITE)
443 swap_variables(
TABLE *, *table, sql_lock->table[i]);
451 (void) unlock_external(thd,table,i-found);
452 sql_lock->table_count=found;
455 table= sql_lock->table;
457 for (i= 0; i < sql_lock->table_count; i++)
460 tbl->lock_position= (uint) (table - sql_lock->table);
461 tbl->lock_data_start= found;
462 found+= tbl->lock_count;
484 for (i=0; i < locked->table_count; i++)
486 if (locked->table[i] == table)
488 uint j, removed_locks, old_tables;
492 DBUG_ASSERT(table->lock_position == i);
498 old_tables= --locked->table_count;
501 removed_locks= table->lock_count;
504 bmove((
char*) (locked->table+i),
505 (
char*) (locked->table+i+1),
506 (old_tables - i) *
sizeof(
TABLE*));
508 lock_data_end= table->lock_data_start + table->lock_count;
510 bmove((
char*) (locked->locks + table->lock_data_start),
511 (
char*) (locked->locks + lock_data_end),
512 (locked->lock_count - lock_data_end) *
523 for (j= i ; j < old_tables; j++)
525 tbl= locked->table[j];
526 tbl->lock_position--;
527 DBUG_ASSERT(tbl->lock_position == j);
528 tbl->lock_data_start-= removed_locks;
532 locked->lock_count-= removed_locks;
545 DBUG_ENTER(
"mysql_lock_abort");
547 if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK)))
549 for (uint i=0; i < locked->lock_count; i++)
550 thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
573 DBUG_ENTER(
"mysql_lock_abort_for_thread");
575 if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK)))
577 for (uint i=0; i < locked->lock_count; i++)
579 if (thr_abort_locks_for_thread(locked->locks[i]->lock,
580 table->in_use->thread_id))
593 DBUG_ENTER(
"mysql_lock_merge");
596 my_malloc(
sizeof(*sql_lock)+
598 sizeof(
TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
600 sql_lock->lock_count=a->lock_count+b->lock_count;
601 sql_lock->table_count=a->table_count+b->table_count;
603 sql_lock->table=(
TABLE**) (sql_lock->locks+sql_lock->lock_count);
604 memcpy(sql_lock->locks,a->locks,a->lock_count*
sizeof(*a->locks));
605 memcpy(sql_lock->locks+a->lock_count,b->locks,
606 b->lock_count*
sizeof(*b->locks));
607 memcpy(sql_lock->table,a->table,a->table_count*
sizeof(*a->table));
608 memcpy(sql_lock->table+a->table_count,b->table,
609 b->table_count*
sizeof(*b->table));
615 for (table= sql_lock->table + a->table_count,
616 end_table= table + b->table_count;
620 (*table)->lock_position+= a->table_count;
621 (*table)->lock_data_start+= a->lock_count;
628 thr_lock_merge_status(sql_lock->locks, sql_lock->lock_count);
629 DBUG_RETURN(sql_lock);
635 static int unlock_external(THD *thd,
TABLE **table,uint count)
637 int error,error_code;
638 DBUG_ENTER(
"unlock_external");
643 if ((*table)->current_lock != F_UNLCK)
645 (*table)->current_lock = F_UNLCK;
646 if ((error=(*table)->file->ha_external_lock(thd, F_UNLCK)))
649 print_lock_error(error_code, (*table)->file->table_type());
654 DBUG_RETURN(error_code);
668 static MYSQL_LOCK *get_lock_data(THD *thd,
TABLE **table_ptr, uint count,
671 uint
i,tables,lock_count;
675 DBUG_ENTER(
"get_lock_data");
677 DBUG_ASSERT((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
678 DBUG_PRINT(
"info", (
"count %d", count));
680 for (i=tables=lock_count=0 ; i < count ; i++)
684 if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
698 my_malloc(
sizeof(*sql_lock) +
700 sizeof(table_ptr) * lock_count,
703 locks= locks_buf= sql_lock->locks= (
THR_LOCK_DATA**) (sql_lock + 1);
704 to= table_buf= sql_lock->table= (
TABLE**) (locks + tables * 2);
705 sql_lock->table_count=lock_count;
707 for (i=0 ; i < count ; i++)
710 enum thr_lock_type lock_type;
713 if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
715 lock_type= table->reginfo.lock_type;
716 DBUG_ASSERT(lock_type != TL_WRITE_DEFAULT && lock_type != TL_READ_DEFAULT);
719 (flags & GET_LOCK_UNLOCK) ? TL_IGNORE :
721 if (flags & GET_LOCK_STORE_LOCKS)
723 table->lock_position= (uint) (to - table_buf);
724 table->lock_data_start= (uint) (locks_start - locks_buf);
725 table->lock_count= (uint) (locks - locks_start);
730 for ( ; org_locks != locks ; org_locks++)
732 (*org_locks)->debug_print_param= (
void *) table;
733 (*org_locks)->m_psi= table->file->
m_psi;
751 sql_lock->lock_count= locks - locks_buf;
752 DBUG_PRINT(
"info", (
"sql_lock->table_count %d sql_lock->lock_count %d",
753 sql_lock->table_count, sql_lock->lock_count));
754 DBUG_RETURN(sql_lock);
781 if (thd->locked_tables_mode)
783 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
784 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
788 if (thd->global_read_lock.can_acquire_protection())
790 global_request.
init(MDL_key::GLOBAL,
"",
"", MDL_INTENTION_EXCLUSIVE,
792 mdl_request.
init(MDL_key::SCHEMA, db,
"", MDL_EXCLUSIVE, MDL_TRANSACTION);
794 mdl_requests.push_front(&mdl_request);
795 mdl_requests.push_front(&global_request);
797 if (thd->mdl_context.acquire_locks(&mdl_requests,
798 thd->variables.lock_wait_timeout))
801 DEBUG_SYNC(thd,
"after_wait_locked_schema_name");
830 const char *db,
const char *
name)
837 if (thd->locked_tables_mode)
839 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
840 ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
845 DEBUG_SYNC(thd,
"before_wait_locked_pname");
847 if (thd->global_read_lock.can_acquire_protection())
849 global_request.
init(MDL_key::GLOBAL,
"",
"", MDL_INTENTION_EXCLUSIVE,
851 schema_request.
init(MDL_key::SCHEMA, db,
"", MDL_INTENTION_EXCLUSIVE,
853 mdl_request.
init(mdl_type, db, name, MDL_EXCLUSIVE, MDL_TRANSACTION);
855 mdl_requests.push_front(&mdl_request);
856 mdl_requests.push_front(&schema_request);
857 mdl_requests.push_front(&global_request);
859 if (thd->mdl_context.acquire_locks(&mdl_requests,
860 thd->variables.lock_wait_timeout))
863 DEBUG_SYNC(thd,
"after_wait_locked_pname");
868 static void print_lock_error(
int error,
const char *table)
870 DBUG_ENTER(
"print_lock_error");
873 case HA_ERR_LOCK_WAIT_TIMEOUT:
874 my_error(ER_LOCK_WAIT_TIMEOUT, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
876 case HA_ERR_READ_ONLY_TRANSACTION:
877 my_error(ER_READ_ONLY_TRANSACTION, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),
880 case HA_ERR_LOCK_DEADLOCK:
881 my_error(ER_LOCK_DEADLOCK, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
883 case HA_ERR_WRONG_COMMAND:
884 my_error(ER_ILLEGAL_HA, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
888 char errbuf[MYSYS_STRERROR_SIZE];
889 my_error(ER_CANT_LOCK, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),
890 error, my_strerror(errbuf,
sizeof(errbuf), error));
966 bool Global_read_lock::lock_global_read_lock(THD *thd)
968 DBUG_ENTER(
"lock_global_read_lock");
974 DBUG_ASSERT(! thd->mdl_context.is_lock_owner(MDL_key::GLOBAL,
"",
"",
976 mdl_request.
init(MDL_key::GLOBAL,
"",
"", MDL_SHARED, MDL_EXPLICIT);
978 if (thd->mdl_context.acquire_lock(&mdl_request,
979 thd->variables.lock_wait_timeout))
982 m_mdl_global_shared_lock= mdl_request.
ticket;
983 m_state= GRL_ACQUIRED;
1007 void Global_read_lock::unlock_global_read_lock(THD *thd)
1009 DBUG_ENTER(
"unlock_global_read_lock");
1011 DBUG_ASSERT(m_mdl_global_shared_lock && m_state);
1013 if (m_mdl_blocks_commits_lock)
1015 thd->mdl_context.release_lock(m_mdl_blocks_commits_lock);
1016 m_mdl_blocks_commits_lock= NULL;
1018 thd->mdl_context.release_lock(m_mdl_global_shared_lock);
1019 m_mdl_global_shared_lock= NULL;
1041 bool Global_read_lock::make_global_read_lock_block_commit(THD *thd)
1044 DBUG_ENTER(
"make_global_read_lock_block_commit");
1049 if (m_state != GRL_ACQUIRED)
1052 mdl_request.
init(MDL_key::COMMIT,
"",
"", MDL_SHARED, MDL_EXPLICIT);
1054 if (thd->mdl_context.acquire_lock(&mdl_request,
1055 thd->variables.lock_wait_timeout))
1058 m_mdl_blocks_commits_lock= mdl_request.
ticket;
1059 m_state= GRL_ACQUIRED_AND_BLOCKS_COMMIT;
1071 void Global_read_lock::set_explicit_lock_duration(THD *thd)
1073 if (m_mdl_global_shared_lock)
1074 thd->mdl_context.set_lock_duration(m_mdl_global_shared_lock, MDL_EXPLICIT);
1075 if (m_mdl_blocks_commits_lock)
1076 thd->mdl_context.set_lock_duration(m_mdl_blocks_commits_lock, MDL_EXPLICIT);