214
session->set_proc_info("Notify start statement");
216
* Here, we advise all storage engines involved in the
217
* statement that we are starting a new statement
219
if (sql_lock->table_count)
221
size_t num_tables= sql_lock->table_count;
222
plugin::StorageEngine *engine;
223
set<size_t> involved_slots;
224
for (size_t x= 1; x <= num_tables; x++, tables++)
226
engine= (*tables)->cursor->engine;
227
if (involved_slots.count(engine->getId()) > 0)
228
continue; /* already added to involved engines */
229
involved_engines.push_back(engine);
230
involved_slots.insert(engine->getId());
233
for_each(involved_engines.begin(),
234
involved_engines.end(),
235
bind2nd(mem_fun(&plugin::StorageEngine::startStatement), session));
238
session->set_proc_info("External lock");
240
* Here, the call to lock_external() informs the
241
* all engines for all tables used in this statement
242
* of the type of lock that Drizzle intends to take on a
204
session->set_proc_info("System lock");
245
205
if (sql_lock->table_count && lock_external(session, sql_lock->table,
246
206
sql_lock->table_count))
473
426
effect is desired.
476
void mysql_lock_remove(Session *session, Table *table)
478
mysql_unlock_some_tables(session, &table, /* table count */ 1);
429
void mysql_lock_remove(Session *session, DRIZZLE_LOCK *locked,Table *table,
432
if (always_unlock == true)
433
mysql_unlock_some_tables(session, &table, /* table count */ 1);
437
for (i=0; i < locked->table_count; i++)
439
if (locked->table[i] == table)
441
uint32_t j, removed_locks, old_tables;
443
uint32_t lock_data_end;
445
assert(table->lock_position == i);
447
/* Unlock if not yet unlocked */
448
if (always_unlock == false)
449
mysql_unlock_some_tables(session, &table, /* table count */ 1);
451
/* Decrement table_count in advance, making below expressions easier */
452
old_tables= --locked->table_count;
454
/* The table has 'removed_locks' lock data elements in locked->locks */
455
removed_locks= table->lock_count;
457
/* Move down all table pointers above 'i'. */
458
memmove((locked->table+i), (locked->table+i+1),
459
(old_tables - i) * sizeof(Table*));
461
lock_data_end= table->lock_data_start + table->lock_count;
462
/* Move down all lock data pointers above 'table->lock_data_end-1' */
463
memmove((locked->locks + table->lock_data_start),
464
(locked->locks + lock_data_end),
465
(locked->lock_count - lock_data_end) *
466
sizeof(THR_LOCK_DATA*));
469
Fix moved table elements.
470
lock_position is the index in the 'locked->table' array,
471
it must be fixed by one.
472
table->lock_data_start is pointer to the lock data for this table
473
in the 'locked->locks' array, they must be fixed by 'removed_locks',
474
the lock data count of the removed table.
476
for (j= i ; j < old_tables; j++)
478
tbl= locked->table[j];
479
tbl->lock_position--;
480
assert(tbl->lock_position == j);
481
tbl->lock_data_start-= removed_locks;
484
/* Finally adjust lock_count. */
485
locked->lock_count-= removed_locks;
492
/* Downgrade all locks on a table to new WRITE level from WRITE_ONLY */
494
void mysql_lock_downgrade_write(Session *session, Table *table,
495
thr_lock_type new_lock_type)
497
DRIZZLE_LOCK *locked;
498
Table *write_lock_used;
499
if ((locked = get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
502
for (uint32_t i=0; i < locked->lock_count; i++)
503
thr_downgrade_write_lock(locked->locks[i], new_lock_type);
504
free((unsigned char*) locked);
482
509
/** Abort all other threads waiting to get lock in table. */
484
void mysql_lock_abort(Session *session, Table *table)
511
void mysql_lock_abort(Session *session, Table *table, bool upgrade_lock)
486
513
DRIZZLE_LOCK *locked;
487
514
Table *write_lock_used;
489
if ((locked= get_lock_data(session, &table, 1, false,
516
if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
490
517
&write_lock_used)))
492
for (uint32_t x= 0; x < locked->lock_count; x++)
493
thr_abort_locks(locked->locks[x]->lock);
519
for (uint32_t i=0; i < locked->lock_count; i++)
520
thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
494
521
free((unsigned char*) locked);
526
554
free((unsigned char*) locked);
560
DRIZZLE_LOCK *mysql_lock_merge(DRIZZLE_LOCK *a,DRIZZLE_LOCK *b)
562
DRIZZLE_LOCK *sql_lock;
563
Table **table, **end_table;
565
if (!(sql_lock= (DRIZZLE_LOCK*)
566
malloc(sizeof(*sql_lock)+
567
sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
568
sizeof(Table*)*(a->table_count+b->table_count))))
569
return(0); // Fatal error
570
sql_lock->lock_count=a->lock_count+b->lock_count;
571
sql_lock->table_count=a->table_count+b->table_count;
572
sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
573
sql_lock->table=(Table**) (sql_lock->locks+sql_lock->lock_count);
574
memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
575
memcpy(sql_lock->locks+a->lock_count,b->locks,
576
b->lock_count*sizeof(*b->locks));
577
memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table));
578
memcpy(sql_lock->table+a->table_count,b->table,
579
b->table_count*sizeof(*b->table));
582
Now adjust lock_position and lock_data_start for all objects that was
583
moved in 'b' (as there is now all objects in 'a' before these).
585
for (table= sql_lock->table + a->table_count,
586
end_table= table + b->table_count;
590
(*table)->lock_position+= a->table_count;
591
(*table)->lock_data_start+= a->lock_count;
594
/* Delete old, not needed locks */
595
free((unsigned char*) a);
596
free((unsigned char*) b);
602
Find duplicate lock in tables.
604
Temporary tables are ignored here like they are ignored in
605
get_lock_data(). If we allow two opens on temporary tables later,
606
both functions should be checked.
608
@param session The current thread.
609
@param needle The table to check for duplicate lock.
610
@param haystack The list of tables to search for the dup lock.
613
This is mainly meant for MERGE tables in INSERT ... SELECT
614
situations. The 'real', underlying tables can be found only after
615
the MERGE tables are opened. This function assumes that the tables are
619
NULL No duplicate lock found.
621
!NULL First table from 'haystack' that matches a lock on 'needle'.
624
TableList *mysql_lock_have_duplicate(Session *session, TableList *needle,
627
DRIZZLE_LOCK *mylock;
631
THR_LOCK_DATA **lock_locks;
632
THR_LOCK_DATA **table_lock_data;
633
THR_LOCK_DATA **end_data;
634
THR_LOCK_DATA **lock_data2;
635
THR_LOCK_DATA **end_data2;
638
Table may not be defined for derived or view tables.
639
Table may not be part of a lock for delayed operations.
641
if (! (table= needle->table) || ! table->lock_count)
644
/* A temporary table does not have locks. */
645
if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
648
/* Get command lock or LOCK TABLES lock. Maybe empty for INSERT DELAYED. */
649
if (! (mylock= session->lock ? session->lock : session->locked_tables))
652
/* If we have less than two tables, we cannot have duplicates. */
653
if (mylock->table_count < 2)
656
lock_locks= mylock->locks;
657
lock_tables= mylock->table;
659
/* Prepare table related variables that don't change in loop. */
660
assert((table->lock_position < mylock->table_count) &&
661
(table == lock_tables[table->lock_position]));
662
table_lock_data= lock_locks + table->lock_data_start;
663
end_data= table_lock_data + table->lock_count;
665
for (; haystack; haystack= haystack->next_global)
667
if (haystack->placeholder())
669
table2= haystack->table;
670
if (table2->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
673
/* All tables in list must be in lock. */
674
assert((table2->lock_position < mylock->table_count) &&
675
(table2 == lock_tables[table2->lock_position]));
677
for (lock_data2= lock_locks + table2->lock_data_start,
678
end_data2= lock_data2 + table2->lock_count;
679
lock_data2 < end_data2;
682
THR_LOCK_DATA **lock_data;
683
THR_LOCK *lock2= (*lock_data2)->lock;
685
for (lock_data= table_lock_data;
686
lock_data < end_data;
689
if ((*lock_data)->lock == lock2)
531
702
/** Unlock a set of external. */
558
729
@param session Thread handler
559
730
@param table_ptr Pointer to tables that should be locks
560
@param should_lock One of:
561
- false : If we should send TL_IGNORE to store lock
562
- true : Store lock info in Table
732
- GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock
733
- GET_LOCK_STORE_LOCKS : Store lock info in Table
563
734
@param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE
566
737
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
567
bool should_lock, Table **write_lock_used)
738
uint32_t flags, Table **write_lock_used)
569
740
uint32_t i,tables,lock_count;
570
741
DRIZZLE_LOCK *sql_lock;
571
742
THR_LOCK_DATA **locks, **locks_buf, **locks_start;
572
743
Table **to, **table_buf;
745
assert((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
574
747
*write_lock_used=0;
575
for (i= tables= lock_count= 0 ; i < count ; i++)
748
for (i=tables=lock_count=0 ; i < count ; i++)
577
750
Table *t= table_ptr[i];
579
if (! (t->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK)))
752
if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
754
tables+= t->file->lock_count();
648
819
And in the FLUSH case, the memory is released quickly anyway.
650
821
sql_lock->lock_count= locks - locks_buf;
826
/*****************************************************************************
827
Lock table based on the name.
828
This is used when we need total access to a closed, not open table
829
*****************************************************************************/
832
Lock and wait for the named lock.
834
@param session Thread handler
835
@param table_list Lock first table in this list
839
Works together with global read lock.
847
int lock_and_wait_for_table_name(Session *session, TableList *table_list)
852
if (wait_if_global_read_lock(session, 0, 1))
854
pthread_mutex_lock(&LOCK_open);
855
if ((lock_retcode = lock_table_name(session, table_list, true)) < 0)
857
if (lock_retcode && wait_for_locked_table_names(session, table_list))
859
unlock_table_name(session, table_list);
865
pthread_mutex_unlock(&LOCK_open);
866
start_waiting_global_read_lock(session);
1089
Test is 'table' is protected by an exclusive name lock.
1091
@param[in] session The current thread handler
1092
@param[in] table_list Table container containing the single table to be
1095
@note Needs to be protected by LOCK_open mutex.
1097
@return Error status code
1098
@retval TRUE Table is protected
1099
@retval FALSE Table is not protected
1103
is_table_name_exclusively_locked_by_this_thread(Session *session,
1104
TableList *table_list)
1106
char key[MAX_DBKEY_LENGTH];
1107
uint32_t key_length;
1109
key_length= create_table_def_key(session, key, table_list, 0);
1111
return is_table_name_exclusively_locked_by_this_thread(session, (unsigned char *)key,
1117
Test is 'table key' is protected by an exclusive name lock.
1119
@param[in] session The current thread handler.
1121
@param[in] key_length
1123
@note Needs to be protected by LOCK_open mutex
1125
@retval TRUE Table is protected
1126
@retval FALSE Table is not protected
1130
is_table_name_exclusively_locked_by_this_thread(Session *session, unsigned char *key,
1133
HASH_SEARCH_STATE state;
1136
for (table= (Table*) hash_first(&open_cache, key,
1137
key_length, &state);
1139
table= (Table*) hash_next(&open_cache, key,
1140
key_length, &state))
1142
if (table->in_use == session &&
1143
table->open_placeholder == 1 &&
1144
table->s->version == 0)
857
1152
Unlock all tables in list with a name lock.
1155
session Thread handle
860
1157
table_list Names of tables to unlock
862
1159
last_table Don't unlock any tables after this one.
1479
Try to get transactional table locks for the tables in the list.
1482
try_transactional_lock()
1483
session Thread handle
1484
table_list List of tables to lock
1487
This is called if transactional table locks are requested for all
1488
tables in table_list and no non-transactional locks pre-exist.
1491
0 OK. All tables are transactional locked.
1492
1 Error: must fall back to non-transactional locks.
1493
-1 Error: no recovery possible.
1496
int try_transactional_lock(Session *session, TableList *table_list)
1498
uint32_t dummy_counter;
1502
/* Need to open the tables to be able to access engine methods. */
1503
if (open_tables(session, &table_list, &dummy_counter, 0))
1505
/* purecov: begin tested */
1510
/* Required by InnoDB. */
1511
session->in_lock_tables= true;
1513
if ((error= set_handler_table_locks(session, table_list, true)))
1516
Not all transactional locks could be taken. If the error was
1517
something else but "unsupported by storage engine", abort the
1518
execution of this statement.
1520
if (error != HA_ERR_WRONG_COMMAND)
1526
Fall back to non-transactional locks because transactional locks
1527
are unsupported by a storage engine. No need to unlock the
1528
successfully taken transactional locks. They go away at end of
1535
/* We need to explicitly commit if autocommit mode is active. */
1536
(void) ha_autocommit_or_rollback(session, 0);
1537
/* Close the tables. The locks (if taken) persist in the storage engines. */
1538
close_tables_for_reopen(session, &table_list);
1539
session->in_lock_tables= false;
1545
Check if lock method conversion was done and was allowed.
1548
check_transactional_lock()
1549
session Thread handle
1550
table_list List of tables to lock
1554
Lock method conversion can be done during parsing if one of the
1555
locks is non-transactional. It can also happen if non-transactional
1556
table locks exist when the statement is executed or if a storage
1557
engine does not support transactional table locks.
1559
Check if transactional table locks have been converted to
1560
non-transactional and if this was allowed. In a running transaction
1561
or in strict mode lock method conversion is not allowed - report an
1562
error. Otherwise it is allowed - issue a warning.
1565
0 OK. Proceed with non-transactional locks.
1566
-1 Error: Lock conversion is prohibited.
1569
int check_transactional_lock(Session *session, TableList *table_list)
1573
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1575
for (tlist= table_list; tlist; tlist= tlist->next_global)
1579
Unfortunately we cannot use tlist->placeholder() here. This method
1580
returns TRUE if the table is not open, which is always the case
1581
here. Whenever the definition of TableList::placeholder() is
1582
changed, probably this condition needs to be changed too.
1584
if (tlist->derived || tlist->schema_table || !tlist->lock_transactional)
1589
/* We must not convert the lock method in strict mode. */
1591
my_error(ER_NO_AUTO_CONVERT_LOCK_STRICT, MYF(0),
1592
tlist->alias ? tlist->alias : tlist->table_name);
1597
/* We must not convert the lock method within an active transaction. */
1598
if (session->active_transaction())
1600
my_error(ER_NO_AUTO_CONVERT_LOCK_TRANSACTION, MYF(0),
1601
tlist->alias ? tlist->alias : tlist->table_name);
1606
/* Warn about the conversion. */
1607
snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK),
1608
tlist->alias ? tlist->alias : tlist->table_name);
1609
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
1610
ER_WARN_AUTO_CONVERT_LOCK, warn_buff);
1618
Set table locks in the table handler.
1621
set_handler_table_locks()
1622
session Thread handle
1623
table_list List of tables to lock
1624
transactional If to lock transactional or non-transactional
1628
!= 0 Error code from handler::lock_table().
1631
int set_handler_table_locks(Session *session, TableList *table_list,
1637
for (tlist= table_list; tlist; tlist= tlist->next_global)
1640
int lock_timeout= -1; /* Use default for non-transactional locks. */
1642
if (tlist->placeholder())
1645
assert((tlist->lock_type == TL_READ) ||
1646
(tlist->lock_type == TL_READ_NO_INSERT) ||
1647
(tlist->lock_type == TL_WRITE_DEFAULT) ||
1648
(tlist->lock_type == TL_WRITE) ||
1649
(tlist->lock_type == TL_WRITE_LOW_PRIORITY));
1652
Every tlist object has a proper lock_type set. Even if it came in
1653
the list as a base table from a view only.
1655
lock_type= ((tlist->lock_type <= TL_READ_NO_INSERT) ?
1656
HA_LOCK_IN_SHARE_MODE : HA_LOCK_IN_EXCLUSIVE_MODE);
1661
The lock timeout is not set if this table belongs to a view. We
1662
need to take it from the top-level view. After this loop
1663
iteration, lock_timeout is not needed any more. Not even if the
1664
locks are converted to non-transactional locks later.
1665
Non-transactional locks do not support a lock_timeout.
1667
lock_timeout= tlist->top_table()->lock_timeout;
1670
For warning/error reporting we need to set the intended lock
1671
method in the TableList object. It will be used later by
1672
check_transactional_lock(). The lock method is not set if this
1673
table belongs to a view. We can safely set it to transactional
1674
locking here. Even for non-view tables. This function is not
1675
called if non-transactional locking was requested for any
1678
tlist->lock_transactional= true;
1682
Because we need to set the lock method (see above) for all
1683
involved tables, we cannot break the loop on an error.
1684
But we do not try more locks after the first error.
1685
However, for non-transactional locking handler::lock_table() is
1686
a hint only. So we continue to call it for other tables.
1688
if (!error || !transactional)
1690
error= tlist->table->file->lock_table(session, lock_type, lock_timeout);
1691
if (error && transactional && (error != HA_ERR_WRONG_COMMAND))
1692
tlist->table->file->print_error(error, MYF(0));
1179
1701
@} (end of group Locking)
1182
} /* namespace drizzled */