Backport of:
------------------------------------------------------------ revno: 2630.4.16 committer: Dmitry Lenev <dlenev@mysql.com> branch nick: mysql-6.0-3726-w timestamp: Thu 2008-05-29 09:45:02 +0400 message: WL#3726 "DDL locking for all metadata objects". After review changes in progress. Tweaked some comments and did some renames to avoid ambiguites.
This commit is contained in:
parent
3d19fdad34
commit
f56cc2a335
@ -1227,7 +1227,6 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
|
|||||||
bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
|
bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
|
||||||
char *cache_key, uint cache_key_length,
|
char *cache_key, uint cache_key_length,
|
||||||
MEM_ROOT *mem_root, uint flags);
|
MEM_ROOT *mem_root, uint flags);
|
||||||
bool name_lock_locked_table(THD *thd, TABLE_LIST *tables);
|
|
||||||
bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list);
|
bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list);
|
||||||
TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name);
|
TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name);
|
||||||
TABLE *find_write_locked_table(TABLE *list, const char *db,
|
TABLE *find_write_locked_table(TABLE *list, const char *db,
|
||||||
|
135
sql/sql_base.cc
135
sql/sql_base.cc
@ -2340,39 +2340,6 @@ void wait_for_condition(THD *thd, pthread_mutex_t *mutex, pthread_cond_t *cond)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Exclusively name-lock a table that is already write-locked by the
|
|
||||||
current thread.
|
|
||||||
|
|
||||||
@param thd current thread context
|
|
||||||
@param tables table list containing one table to open.
|
|
||||||
|
|
||||||
@return FALSE on success, TRUE otherwise.
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool name_lock_locked_table(THD *thd, TABLE_LIST *tables)
|
|
||||||
{
|
|
||||||
bool result= TRUE;
|
|
||||||
|
|
||||||
DBUG_ENTER("name_lock_locked_table");
|
|
||||||
|
|
||||||
/* Under LOCK TABLES we must only accept write locked tables. */
|
|
||||||
tables->table= find_write_locked_table(thd->open_tables, tables->db,
|
|
||||||
tables->table_name);
|
|
||||||
|
|
||||||
if (tables->table)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Ensures that table is opened only by this thread and that no
|
|
||||||
other statement will open this table.
|
|
||||||
*/
|
|
||||||
result= wait_while_table_is_used(thd, tables->table, HA_EXTRA_FORCE_REOPEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
DBUG_RETURN(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Open table for which this thread has exclusive meta-data lock.
|
Open table for which this thread has exclusive meta-data lock.
|
||||||
|
|
||||||
@ -2576,9 +2543,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
/* Parsing of partitioning information from .frm needs thd->lex set up. */
|
/* Parsing of partitioning information from .frm needs thd->lex set up. */
|
||||||
DBUG_ASSERT(thd->lex->is_lex_started);
|
DBUG_ASSERT(thd->lex->is_lex_started);
|
||||||
|
|
||||||
/* find a unused table in the open table cache */
|
*action= OT_NO_ACTION;
|
||||||
if (action)
|
|
||||||
*action= OT_NO_ACTION;
|
|
||||||
|
|
||||||
/* an open table operation needs a lot of the stack space */
|
/* an open table operation needs a lot of the stack space */
|
||||||
if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (uchar *)&alias))
|
if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (uchar *)&alias))
|
||||||
@ -2716,6 +2681,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
enum legacy_db_type not_used;
|
enum legacy_db_type not_used;
|
||||||
build_table_filename(path, sizeof(path) - 1,
|
build_table_filename(path, sizeof(path) - 1,
|
||||||
table_list->db, table_list->table_name, reg_ext, 0);
|
table_list->db, table_list->table_name, reg_ext, 0);
|
||||||
|
/*
|
||||||
|
Note that we can't be 100% sure that it is a view since it's
|
||||||
|
possible that we either simply have not found unused TABLE
|
||||||
|
instance in THD::open_tables list or were unable to open table
|
||||||
|
during prelocking process (in this case in theory we still
|
||||||
|
should hold shared metadata lock on it).
|
||||||
|
*/
|
||||||
if (mysql_frm_type(thd, path, ¬_used) == FRMTYPE_VIEW)
|
if (mysql_frm_type(thd, path, ¬_used) == FRMTYPE_VIEW)
|
||||||
{
|
{
|
||||||
if (!tdc_open_view(thd, table_list, alias, key, key_length,
|
if (!tdc_open_view(thd, table_list, alias, key, key_length,
|
||||||
@ -2741,28 +2713,25 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Non pre-locked/LOCK TABLES mode, and the table is not temporary:
|
Non pre-locked/LOCK TABLES mode, and the table is not temporary.
|
||||||
this is the normal use case.
|
This is the normal use case.
|
||||||
Now we should:
|
|
||||||
- try to find the table in the table cache.
|
|
||||||
- if one of the discovered TABLE instances is name-locked
|
|
||||||
(table->s->version == 0) or some thread has started FLUSH TABLES
|
|
||||||
(refresh_version > table->s->version), back off -- we have to wait
|
|
||||||
until no one holds a name lock on the table.
|
|
||||||
- if there is no such TABLE in the name cache, read the table definition
|
|
||||||
and insert it into the cache.
|
|
||||||
We perform all of the above under LOCK_open which currently protects
|
|
||||||
the open cache (also known as table cache) and table definitions stored
|
|
||||||
on disk.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
mdl_lock= table_list->mdl_lock;
|
mdl_lock= table_list->mdl_lock;
|
||||||
mdl_add_lock(&thd->mdl_context, mdl_lock);
|
mdl_add_lock(&thd->mdl_context, mdl_lock);
|
||||||
|
|
||||||
if (table_list->open_table_type)
|
if (table_list->open_type)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
In case of CREATE TABLE .. If NOT EXISTS .. SELECT, the table
|
||||||
|
may not yet exist. Let's acquire an exclusive lock for that
|
||||||
|
case. If later it turns out the table existsed, we will
|
||||||
|
downgrade the lock to shared. Note that, according to the
|
||||||
|
locking protocol, all exclusive locks must be acquired before
|
||||||
|
shared locks. This invariant is preserved here and is also
|
||||||
|
enforced by asserts in metadata locking subsystem.
|
||||||
|
*/
|
||||||
mdl_set_lock_type(mdl_lock, MDL_EXCLUSIVE);
|
mdl_set_lock_type(mdl_lock, MDL_EXCLUSIVE);
|
||||||
/* TODO: This case can be significantly optimized. */
|
|
||||||
if (mdl_acquire_exclusive_locks(&thd->mdl_context))
|
if (mdl_acquire_exclusive_locks(&thd->mdl_context))
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
@ -2776,7 +2745,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
MDL_HIGH_PRIO : MDL_NORMAL_PRIO);
|
MDL_HIGH_PRIO : MDL_NORMAL_PRIO);
|
||||||
if (mdl_acquire_shared_lock(mdl_lock, &retry))
|
if (mdl_acquire_shared_lock(mdl_lock, &retry))
|
||||||
{
|
{
|
||||||
if (action && retry)
|
if (retry)
|
||||||
*action= OT_BACK_OFF_AND_RETRY;
|
*action= OT_BACK_OFF_AND_RETRY;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
@ -2798,13 +2767,12 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
! (flags & MYSQL_LOCK_IGNORE_FLUSH))
|
! (flags & MYSQL_LOCK_IGNORE_FLUSH))
|
||||||
{
|
{
|
||||||
/* Someone did a refresh while thread was opening tables */
|
/* Someone did a refresh while thread was opening tables */
|
||||||
if (action)
|
*action= OT_BACK_OFF_AND_RETRY;
|
||||||
*action= OT_BACK_OFF_AND_RETRY;
|
|
||||||
pthread_mutex_unlock(&LOCK_open);
|
pthread_mutex_unlock(&LOCK_open);
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (table_list->open_table_type == TABLE_LIST::OPEN_OR_CREATE)
|
if (table_list->open_type == TABLE_LIST::OPEN_OR_CREATE)
|
||||||
{
|
{
|
||||||
bool exists;
|
bool exists;
|
||||||
|
|
||||||
@ -2818,7 +2786,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
}
|
}
|
||||||
/* Table exists. Let us try to open it. */
|
/* Table exists. Let us try to open it. */
|
||||||
}
|
}
|
||||||
else if (table_list->open_table_type == TABLE_LIST::TAKE_EXCLUSIVE_MDL)
|
else if (table_list->open_type == TABLE_LIST::TAKE_EXCLUSIVE_MDL)
|
||||||
{
|
{
|
||||||
pthread_mutex_unlock(&LOCK_open);
|
pthread_mutex_unlock(&LOCK_open);
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
@ -2926,8 +2894,17 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
{
|
{
|
||||||
if (!(flags & MYSQL_LOCK_IGNORE_FLUSH))
|
if (!(flags & MYSQL_LOCK_IGNORE_FLUSH))
|
||||||
{
|
{
|
||||||
if (action)
|
/*
|
||||||
*action= OT_BACK_OFF_AND_RETRY;
|
We already have an MDL lock. But we have encountered an old
|
||||||
|
version of table in the table definition cache which is possible
|
||||||
|
when someone changes the table version directly in the cache
|
||||||
|
without acquiring a metadata lock (e.g. this can happen during
|
||||||
|
"rolling" FLUSH TABLE(S)).
|
||||||
|
Note, that to avoid a "busywait" in this case, we have to wait
|
||||||
|
separately in the caller for old table versions to go away
|
||||||
|
(see tdc_wait_for_old_versions()).
|
||||||
|
*/
|
||||||
|
*action= OT_BACK_OFF_AND_RETRY;
|
||||||
release_table_share(share);
|
release_table_share(share);
|
||||||
pthread_mutex_unlock(&LOCK_open);
|
pthread_mutex_unlock(&LOCK_open);
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
@ -2966,18 +2943,15 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
{
|
{
|
||||||
my_free(table, MYF(0));
|
my_free(table, MYF(0));
|
||||||
|
|
||||||
if (action)
|
if (error == 7)
|
||||||
{
|
{
|
||||||
if (error == 7)
|
share->version= 0;
|
||||||
{
|
*action= OT_DISCOVER;
|
||||||
share->version= 0;
|
}
|
||||||
*action= OT_DISCOVER;
|
else if (share->crashed)
|
||||||
}
|
{
|
||||||
else if (share->crashed)
|
share->version= 0;
|
||||||
{
|
*action= OT_REPAIR;
|
||||||
share->version= 0;
|
|
||||||
*action= OT_REPAIR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
goto err_unlock;
|
goto err_unlock;
|
||||||
@ -2996,16 +2970,19 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
|
|||||||
|
|
||||||
pthread_mutex_unlock(&LOCK_open);
|
pthread_mutex_unlock(&LOCK_open);
|
||||||
|
|
||||||
// Table existed
|
/*
|
||||||
if (table_list->open_table_type == TABLE_LIST::OPEN_OR_CREATE)
|
In CREATE TABLE .. If NOT EXISTS .. SELECT we have found that
|
||||||
|
table exists now we should downgrade our exclusive metadata
|
||||||
|
lock on this table to shared metadata lock.
|
||||||
|
*/
|
||||||
|
if (table_list->open_type == TABLE_LIST::OPEN_OR_CREATE)
|
||||||
mdl_downgrade_exclusive_locks(&thd->mdl_context);
|
mdl_downgrade_exclusive_locks(&thd->mdl_context);
|
||||||
|
|
||||||
table->mdl_lock= mdl_lock;
|
table->mdl_lock= mdl_lock;
|
||||||
if (action)
|
|
||||||
{
|
table->next=thd->open_tables; /* Link into simple list */
|
||||||
table->next=thd->open_tables; /* Link into simple list */
|
thd->open_tables=table;
|
||||||
thd->open_tables=table;
|
|
||||||
}
|
|
||||||
table->reginfo.lock_type=TL_READ; /* Assume read */
|
table->reginfo.lock_type=TL_READ; /* Assume read */
|
||||||
|
|
||||||
reset:
|
reset:
|
||||||
@ -3856,8 +3833,8 @@ err:
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Auxiliary routine which finalizes process of TABLE object creation
|
Finalize the process of TABLE creation by loading table triggers
|
||||||
by loading triggers and handling implicitly emptied tables.
|
and taking action if a HEAP table content was emptied implicitly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry)
|
static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry)
|
||||||
@ -4636,7 +4613,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
|||||||
table and successful table creation.
|
table and successful table creation.
|
||||||
...
|
...
|
||||||
*/
|
*/
|
||||||
if (tables->open_table_type)
|
if (tables->open_type)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (action)
|
if (action)
|
||||||
|
@ -798,6 +798,7 @@ void mysql_ha_flush(THD *thd)
|
|||||||
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
|
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
|
||||||
{
|
{
|
||||||
hash_tables= (TABLE_LIST*) my_hash_element(&thd->handler_tables_hash, i);
|
hash_tables= (TABLE_LIST*) my_hash_element(&thd->handler_tables_hash, i);
|
||||||
|
/* TABLE::mdl_lock is 0 for temporary tables so we need extra check. */
|
||||||
if (hash_tables->table &&
|
if (hash_tables->table &&
|
||||||
(hash_tables->table->mdl_lock &&
|
(hash_tables->table->mdl_lock &&
|
||||||
mdl_has_pending_conflicting_lock(hash_tables->table->mdl_lock) ||
|
mdl_has_pending_conflicting_lock(hash_tables->table->mdl_lock) ||
|
||||||
|
@ -3453,6 +3453,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
|||||||
Item *item;
|
Item *item;
|
||||||
Field *tmp_field;
|
Field *tmp_field;
|
||||||
bool not_used;
|
bool not_used;
|
||||||
|
enum_open_table_action not_used2;
|
||||||
DBUG_ENTER("create_table_from_items");
|
DBUG_ENTER("create_table_from_items");
|
||||||
|
|
||||||
tmp_table.alias= 0;
|
tmp_table.alias= 0;
|
||||||
@ -3544,8 +3545,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!(table= open_table(thd, create_table, thd->mem_root,
|
if (!(table= open_table(thd, create_table, thd->mem_root, ¬_used2,
|
||||||
(enum_open_table_action*) 0,
|
|
||||||
MYSQL_OPEN_TEMPORARY_ONLY)) &&
|
MYSQL_OPEN_TEMPORARY_ONLY)) &&
|
||||||
!create_info->table_existed)
|
!create_info->table_existed)
|
||||||
{
|
{
|
||||||
|
@ -2631,7 +2631,7 @@ case SQLCOM_PREPARE:
|
|||||||
if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
|
if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
|
||||||
{
|
{
|
||||||
lex->link_first_table_back(create_table, link_to_local);
|
lex->link_first_table_back(create_table, link_to_local);
|
||||||
create_table->open_table_type= TABLE_LIST::OPEN_OR_CREATE;
|
create_table->open_type= TABLE_LIST::OPEN_OR_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(res= open_and_lock_tables(thd, lex->query_tables)))
|
if (!(res= open_and_lock_tables(thd, lex->query_tables)))
|
||||||
|
@ -1673,7 +1673,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
|
|||||||
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
|
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
|
||||||
{
|
{
|
||||||
lex->link_first_table_back(create_table, link_to_local);
|
lex->link_first_table_back(create_table, link_to_local);
|
||||||
create_table->open_table_type= TABLE_LIST::OPEN_OR_CREATE;
|
create_table->open_type= TABLE_LIST::OPEN_OR_CREATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
|
if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
|
||||||
|
@ -7208,12 +7208,13 @@ view_err:
|
|||||||
{
|
{
|
||||||
if (table->s->tmp_table)
|
if (table->s->tmp_table)
|
||||||
{
|
{
|
||||||
|
enum_open_table_action not_used;
|
||||||
TABLE_LIST tbl;
|
TABLE_LIST tbl;
|
||||||
bzero((void*) &tbl, sizeof(tbl));
|
bzero((void*) &tbl, sizeof(tbl));
|
||||||
tbl.db= new_db;
|
tbl.db= new_db;
|
||||||
tbl.table_name= tbl.alias= tmp_name;
|
tbl.table_name= tbl.alias= tmp_name;
|
||||||
/* Table is in thd->temporary_tables */
|
/* Table is in thd->temporary_tables */
|
||||||
new_table= open_table(thd, &tbl, thd->mem_root, (enum_open_table_action*) 0,
|
new_table= open_table(thd, &tbl, thd->mem_root, ¬_used,
|
||||||
MYSQL_LOCK_IGNORE_FLUSH);
|
MYSQL_LOCK_IGNORE_FLUSH);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -446,8 +446,17 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
|||||||
|
|
||||||
if (thd->locked_tables)
|
if (thd->locked_tables)
|
||||||
{
|
{
|
||||||
if (name_lock_locked_table(thd, tables))
|
/* Under LOCK TABLES we must only accept write locked tables. */
|
||||||
|
if (!(tables->table= find_write_locked_table(thd->open_tables, tables->db,
|
||||||
|
tables->table_name)))
|
||||||
goto end;
|
goto end;
|
||||||
|
/*
|
||||||
|
Ensure that table is opened only by this thread and that no other
|
||||||
|
statement will open this table.
|
||||||
|
*/
|
||||||
|
if (wait_while_table_is_used(thd, tables->table, HA_EXTRA_FORCE_REOPEN))
|
||||||
|
goto end;
|
||||||
|
|
||||||
pthread_mutex_lock(&LOCK_open);
|
pthread_mutex_lock(&LOCK_open);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -395,7 +395,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
|
|||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
lex->link_first_table_back(view, link_to_local);
|
lex->link_first_table_back(view, link_to_local);
|
||||||
view->open_table_type= TABLE_LIST::TAKE_EXCLUSIVE_MDL;
|
view->open_type= TABLE_LIST::TAKE_EXCLUSIVE_MDL;
|
||||||
|
|
||||||
if (open_and_lock_tables(thd, lex->query_tables))
|
if (open_and_lock_tables(thd, lex->query_tables))
|
||||||
{
|
{
|
||||||
|
26
sql/table.h
26
sql/table.h
@ -1349,14 +1349,26 @@ struct TABLE_LIST
|
|||||||
used for implicit LOCK TABLES only and won't be used in real statement.
|
used for implicit LOCK TABLES only and won't be used in real statement.
|
||||||
*/
|
*/
|
||||||
bool prelocking_placeholder;
|
bool prelocking_placeholder;
|
||||||
/*
|
/**
|
||||||
This TABLE_LIST object corresponds to the table/view which requires
|
Indicates that if TABLE_LIST object corresponds to the table/view
|
||||||
special handling/meta-data locking. For example this is a target
|
which requires special handling/meta-data locking.
|
||||||
table in CREATE TABLE ... SELECT so it is possible that it does not
|
|
||||||
exist and we should take exclusive meta-data lock on it in this
|
|
||||||
case.
|
|
||||||
*/
|
*/
|
||||||
enum {NORMAL_OPEN= 0, OPEN_OR_CREATE, TAKE_EXCLUSIVE_MDL} open_table_type;
|
enum
|
||||||
|
{
|
||||||
|
/* Normal open, shared metadata lock should be taken. */
|
||||||
|
NORMAL_OPEN= 0,
|
||||||
|
/*
|
||||||
|
It's target table of CREATE TABLE ... SELECT so we should
|
||||||
|
either open table if it exists (and take shared metadata lock)
|
||||||
|
or take exclusive metadata lock if it doesn't exist.
|
||||||
|
*/
|
||||||
|
OPEN_OR_CREATE,
|
||||||
|
/*
|
||||||
|
It's target view of CREATE/ALTER VIEW. We should take exclusive
|
||||||
|
metadata lock for this table list element.
|
||||||
|
*/
|
||||||
|
TAKE_EXCLUSIVE_MDL
|
||||||
|
} open_type;
|
||||||
/**
|
/**
|
||||||
Indicates that for this table/view we need to take shared metadata
|
Indicates that for this table/view we need to take shared metadata
|
||||||
lock which should be upgradable to exclusive metadata lock.
|
lock which should be upgradable to exclusive metadata lock.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user