~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to sql/lock.cc

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2006 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
/**
 
18
  @file
 
19
 
 
20
  Locking functions for mysql.
 
21
 
 
22
  Because of the new concurrent inserts, we must first get external locks
 
23
  before getting internal locks.  If we do it in the other order, the status
 
24
  information is not up to date when called from the lock handler.
 
25
 
 
26
  GENERAL DESCRIPTION OF LOCKING
 
27
 
 
28
  When not using LOCK TABLES:
 
29
 
 
30
  - For each SQL statement mysql_lock_tables() is called for all involved
 
31
    tables.
 
32
    - mysql_lock_tables() will call
 
33
      table_handler->external_lock(thd,locktype) for each table.
 
34
      This is followed by a call to thr_multi_lock() for all tables.
 
35
 
 
36
  - When statement is done, we call mysql_unlock_tables().
 
37
    This will call thr_multi_unlock() followed by
 
38
    table_handler->external_lock(thd, F_UNLCK) for each table.
 
39
 
 
40
  - Note that mysql_unlock_tables() may be called several times as
 
41
    MySQL in some cases can free some tables earlier than others.
 
42
 
 
43
  - The above is true both for normal and temporary tables.
 
44
 
 
45
  - Temporary non transactional tables are never passed to thr_multi_lock()
 
46
    and we never call external_lock(thd, F_UNLOCK) on these.
 
47
 
 
48
  When using LOCK TABLES:
 
49
 
 
50
  - LOCK TABLE will call mysql_lock_tables() for all tables.
 
51
    mysql_lock_tables() will call
 
52
    table_handler->external_lock(thd,locktype) for each table.
 
53
    This is followed by a call to thr_multi_lock() for all tables.
 
54
 
 
55
  - For each statement, we will call table_handler->start_stmt(THD)
 
56
    to inform the table handler that we are using the table.
 
57
 
 
58
    The tables used can only be tables used in LOCK TABLES or a
 
59
    temporary table.
 
60
 
 
61
  - When statement is done, we will call ha_commit_stmt(thd);
 
62
 
 
63
  - When calling UNLOCK TABLES we call mysql_unlock_tables() for all
 
64
    tables used in LOCK TABLES
 
65
 
 
66
  If table_handler->external_lock(thd, locktype) fails, we call
 
67
  table_handler->external_lock(thd, F_UNLCK) for each table that was locked,
 
68
  excluding one that caused failure. That means handler must cleanup itself
 
69
  in case external_lock() fails.
 
70
 
 
71
  @todo
 
72
  Change to use my_malloc() ONLY when using LOCK TABLES command or when
 
73
  we are forced to use mysql_lock_merge.
 
74
*/
 
75
 
 
76
#include "mysql_priv.h"
 
77
#include <hash.h>
 
78
#include <assert.h>
 
79
 
 
80
/**
 
81
  @defgroup Locking Locking
 
82
  @{
 
83
*/
 
84
 
 
85
extern HASH open_cache;
 
86
 
 
87
/* flags for get_lock_data */
 
88
#define GET_LOCK_UNLOCK         1
 
89
#define GET_LOCK_STORE_LOCKS    2
 
90
 
 
91
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
 
92
                                 uint flags, TABLE **write_locked);
 
93
static int lock_external(THD *thd, TABLE **table,uint count);
 
94
static int unlock_external(THD *thd, TABLE **table,uint count);
 
95
static void print_lock_error(int error, const char *);
 
96
 
 
97
/*
 
98
  Lock tables.
 
99
 
 
100
  SYNOPSIS
 
101
    mysql_lock_tables()
 
102
    thd                         The current thread.
 
103
    tables                      An array of pointers to the tables to lock.
 
104
    count                       The number of tables to lock.
 
105
    flags                       Options:
 
106
      MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK      Ignore a global read lock
 
107
      MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY      Ignore SET GLOBAL READ_ONLY
 
108
      MYSQL_LOCK_IGNORE_FLUSH                 Ignore a flush tables.
 
109
      MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN        Instead of reopening altered
 
110
                                              or dropped tables by itself,
 
111
                                              mysql_lock_tables() should
 
112
                                              notify upper level and rely
 
113
                                              on caller doing this.
 
114
    need_reopen                 Out parameter, TRUE if some tables were altered
 
115
                                or deleted and should be reopened by caller.
 
116
 
 
117
  RETURN
 
118
    A lock structure pointer on success.
 
119
    NULL on error or if some tables should be reopen.
 
120
*/
 
121
 
 
122
/* Map the return value of thr_lock to an error from errmsg.txt */
 
123
static int thr_lock_errno_to_mysql[]=
 
124
{ 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
 
125
 
 
126
/**
 
127
  Perform semantic checks for mysql_lock_tables.
 
128
  @param thd The current thread
 
129
  @param tables The tables to lock
 
130
  @param count The number of tables to lock
 
131
  @param flags Lock flags
 
132
  @return 0 if all the check passed, non zero if a check failed.
 
133
*/
 
134
int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
 
135
{
 
136
  uint system_count;
 
137
  uint i;
 
138
 
 
139
  DBUG_ENTER("mysql_lock_tables_check");
 
140
 
 
141
  system_count= 0;
 
142
 
 
143
  for (i=0 ; i<count; i++)
 
144
  {
 
145
    TABLE *t= tables[i];
 
146
 
 
147
    /* Protect against 'fake' partially initialized TABLE_SHARE */
 
148
    DBUG_ASSERT(t->s->table_category != TABLE_UNKNOWN_CATEGORY);
 
149
 
 
150
    if ((t->s->table_category == TABLE_CATEGORY_SYSTEM) &&
 
151
        (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE))
 
152
    {
 
153
      system_count++;
 
154
    }
 
155
  }
 
156
 
 
157
  /*
 
158
    Locking of system tables is restricted:
 
159
    locking a mix of system and non-system tables in the same lock
 
160
    is prohibited, to prevent contention.
 
161
  */
 
162
  if ((system_count > 0) && (system_count < count))
 
163
  {
 
164
    my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0));
 
165
    DBUG_RETURN(1);
 
166
  }
 
167
 
 
168
  DBUG_RETURN(0);
 
169
}
 
170
 
 
171
 
 
172
/**
 
173
  Reset lock type in lock data and free.
 
174
 
 
175
  @param mysql_lock Lock structures to reset.
 
176
 
 
177
  @note After a locking error we want to quit the locking of the table(s).
 
178
        The test case in the bug report for Bug #18544 has the following
 
179
        cases: 1. Locking error in lock_external() due to InnoDB timeout.
 
180
        2. Locking error in get_lock_data() due to missing write permission.
 
181
        3. Locking error in wait_if_global_read_lock() due to lock conflict.
 
182
 
 
183
  @note In all these cases we have already set the lock type into the lock
 
184
        data of the open table(s). If the table(s) are in the open table
 
185
        cache, they could be reused with the non-zero lock type set. This
 
186
        could lead to ignoring a different lock type with the next lock.
 
187
 
 
188
  @note Clear the lock type of all lock data. This ensures that the next
 
189
        lock request will set its lock type properly.
 
190
*/
 
191
 
 
192
static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock)
 
193
{
 
194
  MYSQL_LOCK *sql_lock= *mysql_lock;
 
195
  THR_LOCK_DATA **ldata, **ldata_end;
 
196
 
 
197
  /* Clear the lock type of all lock data to avoid reusage. */
 
198
  for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count;
 
199
       ldata < ldata_end;
 
200
       ldata++)
 
201
  {
 
202
    /* Reset lock type. */
 
203
    (*ldata)->type= TL_UNLOCK;
 
204
  }
 
205
  my_free((uchar*) sql_lock, MYF(0));
 
206
  *mysql_lock= 0;
 
207
}
 
208
 
 
209
 
 
210
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
 
211
                              uint flags, bool *need_reopen)
 
212
{
 
213
  MYSQL_LOCK *sql_lock;
 
214
  TABLE *write_lock_used;
 
215
  int rc;
 
216
 
 
217
  DBUG_ENTER("mysql_lock_tables");
 
218
 
 
219
  *need_reopen= FALSE;
 
220
 
 
221
  if (mysql_lock_tables_check(thd, tables, count, flags))
 
222
    DBUG_RETURN (NULL);
 
223
 
 
224
  for (;;)
 
225
  {
 
226
    if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
 
227
                                   &write_lock_used)))
 
228
      break;
 
229
 
 
230
    if (global_read_lock && write_lock_used &&
 
231
        ! (flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK))
 
232
    {
 
233
      /*
 
234
        Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
 
235
        Wait until the lock is gone
 
236
      */
 
237
      if (wait_if_global_read_lock(thd, 1, 1))
 
238
      {
 
239
        /* Clear the lock type of all lock data to avoid reusage. */
 
240
        reset_lock_data_and_free(&sql_lock);
 
241
        break;
 
242
      }
 
243
      if (thd->version != refresh_version)
 
244
      {
 
245
        /* Clear the lock type of all lock data to avoid reusage. */
 
246
        reset_lock_data_and_free(&sql_lock);
 
247
        goto retry;
 
248
      }
 
249
    }
 
250
 
 
251
    if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) &&
 
252
        write_lock_used &&
 
253
        opt_readonly &&
 
254
        !thd->slave_thread)
 
255
    {
 
256
      /*
 
257
        Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock.
 
258
        We do not wait for READ_ONLY=0, and fail.
 
259
      */
 
260
      reset_lock_data_and_free(&sql_lock);
 
261
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
 
262
      break;
 
263
    }
 
264
 
 
265
    thd_proc_info(thd, "System lock");
 
266
    DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
 
267
    if (sql_lock->table_count && lock_external(thd, sql_lock->table,
 
268
                                               sql_lock->table_count))
 
269
    {
 
270
      /* Clear the lock type of all lock data to avoid reusage. */
 
271
      reset_lock_data_and_free(&sql_lock);
 
272
      break;
 
273
    }
 
274
    thd_proc_info(thd, "Table lock");
 
275
    DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
 
276
    /* Copy the lock data array. thr_multi_lock() reorders its contens. */
 
277
    memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
 
278
           sql_lock->lock_count * sizeof(*sql_lock->locks));
 
279
    /* Lock on the copied half of the lock data array. */
 
280
    rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
 
281
                                                     sql_lock->lock_count,
 
282
                                                     sql_lock->lock_count,
 
283
                                                     thd->lock_id)];
 
284
    if (rc > 1)                                 /* a timeout or a deadlock */
 
285
    {
 
286
      if (sql_lock->table_count)
 
287
        VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
 
288
      reset_lock_data_and_free(&sql_lock);
 
289
      my_error(rc, MYF(0));
 
290
      break;
 
291
    }
 
292
    else if (rc == 1)                           /* aborted */
 
293
    {
 
294
      thd->some_tables_deleted=1;               // Try again
 
295
      sql_lock->lock_count= 0;                  // Locks are already freed
 
296
      // Fall through: unlock, reset lock data, free and retry
 
297
    }
 
298
    else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH))
 
299
    {
 
300
      /*
 
301
        Thread was killed or lock aborted. Let upper level close all
 
302
        used tables and retry or give error.
 
303
      */
 
304
      break;
 
305
    }
 
306
    else if (!thd->open_tables)
 
307
    {
 
308
      // Only using temporary tables, no need to unlock
 
309
      thd->some_tables_deleted=0;
 
310
      break;
 
311
    }
 
312
    thd_proc_info(thd, 0);
 
313
 
 
314
    /* going to retry, unlock all tables */
 
315
    if (sql_lock->lock_count)
 
316
        thr_multi_unlock(sql_lock->locks, sql_lock->lock_count);
 
317
 
 
318
    if (sql_lock->table_count)
 
319
      VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
 
320
 
 
321
    /*
 
322
      If thr_multi_lock fails it resets lock type for tables, which
 
323
      were locked before (and including) one that caused error. Lock
 
324
      type for other tables preserved.
 
325
    */
 
326
    reset_lock_data_and_free(&sql_lock);
 
327
retry:
 
328
    if (flags & MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN)
 
329
    {
 
330
      *need_reopen= TRUE;
 
331
      break;
 
332
    }
 
333
    if (wait_for_tables(thd))
 
334
      break;                                    // Couldn't open tables
 
335
  }
 
336
  thd_proc_info(thd, 0);
 
337
  if (thd->killed)
 
338
  {
 
339
    thd->send_kill_message();
 
340
    if (sql_lock)
 
341
    {
 
342
      mysql_unlock_tables(thd,sql_lock);
 
343
      sql_lock=0;
 
344
    }
 
345
  }
 
346
 
 
347
  thd->set_time_after_lock();
 
348
  DBUG_RETURN (sql_lock);
 
349
}
 
350
 
 
351
 
 
352
static int lock_external(THD *thd, TABLE **tables, uint count)
 
353
{
 
354
  register uint i;
 
355
  int lock_type,error;
 
356
  DBUG_ENTER("lock_external");
 
357
 
 
358
  DBUG_PRINT("info", ("count %d", count));
 
359
  for (i=1 ; i <= count ; i++, tables++)
 
360
  {
 
361
    DBUG_ASSERT((*tables)->reginfo.lock_type >= TL_READ);
 
362
    lock_type=F_WRLCK;                          /* Lock exclusive */
 
363
    if ((*tables)->db_stat & HA_READ_ONLY ||
 
364
        ((*tables)->reginfo.lock_type >= TL_READ &&
 
365
         (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
 
366
      lock_type=F_RDLCK;
 
367
 
 
368
    if ((error=(*tables)->file->ha_external_lock(thd,lock_type)))
 
369
    {
 
370
      print_lock_error(error, (*tables)->file->table_type());
 
371
      while (--i)
 
372
      {
 
373
        tables--;
 
374
        (*tables)->file->ha_external_lock(thd, F_UNLCK);
 
375
        (*tables)->current_lock=F_UNLCK;
 
376
      }
 
377
      DBUG_RETURN(error);
 
378
    }
 
379
    else
 
380
    {
 
381
      (*tables)->db_stat &= ~ HA_BLOCK_LOCK;
 
382
      (*tables)->current_lock= lock_type;
 
383
    }
 
384
  }
 
385
  DBUG_RETURN(0);
 
386
}
 
387
 
 
388
 
 
389
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
 
390
{
 
391
  DBUG_ENTER("mysql_unlock_tables");
 
392
  if (sql_lock->lock_count)
 
393
    thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
 
394
  if (sql_lock->table_count)
 
395
    VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
 
396
  my_free((uchar*) sql_lock,MYF(0));
 
397
  DBUG_VOID_RETURN;
 
398
}
 
399
 
 
400
/**
 
401
  Unlock some of the tables locked by mysql_lock_tables.
 
402
 
 
403
  This will work even if get_lock_data fails (next unlock will free all)
 
404
*/
 
405
 
 
406
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
 
407
{
 
408
  MYSQL_LOCK *sql_lock;
 
409
  TABLE *write_lock_used;
 
410
  if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK,
 
411
                               &write_lock_used)))
 
412
    mysql_unlock_tables(thd, sql_lock);
 
413
}
 
414
 
 
415
 
 
416
/**
 
417
  unlock all tables locked for read.
 
418
*/
 
419
 
 
420
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
 
421
{
 
422
  uint i,found;
 
423
  DBUG_ENTER("mysql_unlock_read_tables");
 
424
 
 
425
  /* Move all write locks first */
 
426
  THR_LOCK_DATA **lock=sql_lock->locks;
 
427
  for (i=found=0 ; i < sql_lock->lock_count ; i++)
 
428
  {
 
429
    if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
 
430
    {
 
431
      swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]);
 
432
      lock++;
 
433
      found++;
 
434
    }
 
435
  }
 
436
  /* unlock the read locked tables */
 
437
  if (i != found)
 
438
  {
 
439
    thr_multi_unlock(lock,i-found);
 
440
    sql_lock->lock_count= found;
 
441
  }
 
442
 
 
443
  /* Then do the same for the external locks */
 
444
  /* Move all write locked tables first */
 
445
  TABLE **table=sql_lock->table;
 
446
  for (i=found=0 ; i < sql_lock->table_count ; i++)
 
447
  {
 
448
    DBUG_ASSERT(sql_lock->table[i]->lock_position == i);
 
449
    if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
 
450
    {
 
451
      swap_variables(TABLE *, *table, sql_lock->table[i]);
 
452
      table++;
 
453
      found++;
 
454
    }
 
455
  }
 
456
  /* Unlock all read locked tables */
 
457
  if (i != found)
 
458
  {
 
459
    VOID(unlock_external(thd,table,i-found));
 
460
    sql_lock->table_count=found;
 
461
  }
 
462
  /* Fix the lock positions in TABLE */
 
463
  table= sql_lock->table;
 
464
  found= 0;
 
465
  for (i= 0; i < sql_lock->table_count; i++)
 
466
  {
 
467
    TABLE *tbl= *table;
 
468
    tbl->lock_position= table - sql_lock->table;
 
469
    tbl->lock_data_start= found;
 
470
    found+= tbl->lock_count;
 
471
    table++;
 
472
  }
 
473
  DBUG_VOID_RETURN;
 
474
}
 
475
 
 
476
 
 
477
/**
 
478
  Try to find the table in the list of locked tables.
 
479
  In case of success, unlock the table and remove it from this list.
 
480
 
 
481
  @note This function has a legacy side effect: the table is
 
482
  unlocked even if it is not found in the locked list.
 
483
  It's not clear if this side effect is intentional or still
 
484
  desirable. It might lead to unmatched calls to
 
485
  unlock_external(). Moreover, a discrepancy can be left
 
486
  unnoticed by the storage engine, because in
 
487
  unlock_external() we call handler::external_lock(F_UNLCK) only
 
488
  if table->current_lock is not F_UNLCK.
 
489
 
 
490
  @param  thd             thread context
 
491
  @param  locked          list of locked tables
 
492
  @param  table           the table to unlock
 
493
  @param  always_unlock   specify explicitly if the legacy side
 
494
                          effect is desired.
 
495
*/
 
496
 
 
497
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table,
 
498
                       bool always_unlock)
 
499
{
 
500
  if (always_unlock == TRUE)
 
501
    mysql_unlock_some_tables(thd, &table, /* table count */ 1);
 
502
  if (locked)
 
503
  {
 
504
    register uint i;
 
505
    for (i=0; i < locked->table_count; i++)
 
506
    {
 
507
      if (locked->table[i] == table)
 
508
      {
 
509
        uint  j, removed_locks, old_tables;
 
510
        TABLE *tbl;
 
511
        uint lock_data_end;
 
512
 
 
513
        DBUG_ASSERT(table->lock_position == i);
 
514
 
 
515
        /* Unlock if not yet unlocked */
 
516
        if (always_unlock == FALSE)
 
517
          mysql_unlock_some_tables(thd, &table, /* table count */ 1);
 
518
 
 
519
        /* Decrement table_count in advance, making below expressions easier */
 
520
        old_tables= --locked->table_count;
 
521
 
 
522
        /* The table has 'removed_locks' lock data elements in locked->locks */
 
523
        removed_locks= table->lock_count;
 
524
 
 
525
        /* Move down all table pointers above 'i'. */
 
526
        bmove((char*) (locked->table+i),
 
527
              (char*) (locked->table+i+1),
 
528
              (old_tables - i) * sizeof(TABLE*));
 
529
 
 
530
        lock_data_end= table->lock_data_start + table->lock_count;
 
531
        /* Move down all lock data pointers above 'table->lock_data_end-1' */
 
532
        bmove((char*) (locked->locks + table->lock_data_start),
 
533
              (char*) (locked->locks + lock_data_end),
 
534
              (locked->lock_count - lock_data_end) *
 
535
              sizeof(THR_LOCK_DATA*));
 
536
 
 
537
        /*
 
538
          Fix moved table elements.
 
539
          lock_position is the index in the 'locked->table' array,
 
540
          it must be fixed by one.
 
541
          table->lock_data_start is pointer to the lock data for this table
 
542
          in the 'locked->locks' array, they must be fixed by 'removed_locks',
 
543
          the lock data count of the removed table.
 
544
        */
 
545
        for (j= i ; j < old_tables; j++)
 
546
        {
 
547
          tbl= locked->table[j];
 
548
          tbl->lock_position--;
 
549
          DBUG_ASSERT(tbl->lock_position == j);
 
550
          tbl->lock_data_start-= removed_locks;
 
551
        }
 
552
 
 
553
        /* Finally adjust lock_count. */
 
554
        locked->lock_count-= removed_locks;
 
555
        break;
 
556
      }
 
557
    }
 
558
  }
 
559
}
 
560
 
 
561
/* Downgrade all locks on a table to new WRITE level from WRITE_ONLY */
 
562
 
 
563
void mysql_lock_downgrade_write(THD *thd, TABLE *table,
 
564
                                thr_lock_type new_lock_type)
 
565
{
 
566
  MYSQL_LOCK *locked;
 
567
  TABLE *write_lock_used;
 
568
  if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
 
569
                              &write_lock_used)))
 
570
  {
 
571
    for (uint i=0; i < locked->lock_count; i++)
 
572
      thr_downgrade_write_lock(locked->locks[i], new_lock_type);
 
573
    my_free((uchar*) locked,MYF(0));
 
574
  }
 
575
}
 
576
 
 
577
 
 
578
/** Abort all other threads waiting to get lock in table. */
 
579
 
 
580
void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
 
581
{
 
582
  MYSQL_LOCK *locked;
 
583
  TABLE *write_lock_used;
 
584
  DBUG_ENTER("mysql_lock_abort");
 
585
 
 
586
  if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
 
587
                             &write_lock_used)))
 
588
  {
 
589
    for (uint i=0; i < locked->lock_count; i++)
 
590
      thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
 
591
    my_free((uchar*) locked,MYF(0));
 
592
  }
 
593
  DBUG_VOID_RETURN;
 
594
}
 
595
 
 
596
 
 
597
/**
 
598
  Abort one thread / table combination.
 
599
 
 
600
  @param thd       Thread handler
 
601
  @param table     Table that should be removed from lock queue
 
602
 
 
603
  @retval
 
604
    0  Table was not locked by another thread
 
605
  @retval
 
606
    1  Table was locked by at least one other thread
 
607
*/
 
608
 
 
609
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
 
610
{
 
611
  MYSQL_LOCK *locked;
 
612
  TABLE *write_lock_used;
 
613
  bool result= FALSE;
 
614
  DBUG_ENTER("mysql_lock_abort_for_thread");
 
615
 
 
616
  if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
 
617
                             &write_lock_used)))
 
618
  {
 
619
    for (uint i=0; i < locked->lock_count; i++)
 
620
    {
 
621
      if (thr_abort_locks_for_thread(locked->locks[i]->lock,
 
622
                                     table->in_use->thread_id))
 
623
        result= TRUE;
 
624
    }
 
625
    my_free((uchar*) locked,MYF(0));
 
626
  }
 
627
  DBUG_RETURN(result);
 
628
}
 
629
 
 
630
 
 
631
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
 
632
{
 
633
  MYSQL_LOCK *sql_lock;
 
634
  TABLE **table, **end_table;
 
635
  DBUG_ENTER("mysql_lock_merge");
 
636
 
 
637
  if (!(sql_lock= (MYSQL_LOCK*)
 
638
        my_malloc(sizeof(*sql_lock)+
 
639
                  sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
 
640
                  sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
 
641
    DBUG_RETURN(0);                             // Fatal error
 
642
  sql_lock->lock_count=a->lock_count+b->lock_count;
 
643
  sql_lock->table_count=a->table_count+b->table_count;
 
644
  sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
 
645
  sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count);
 
646
  memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
 
647
  memcpy(sql_lock->locks+a->lock_count,b->locks,
 
648
         b->lock_count*sizeof(*b->locks));
 
649
  memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table));
 
650
  memcpy(sql_lock->table+a->table_count,b->table,
 
651
         b->table_count*sizeof(*b->table));
 
652
 
 
653
  /*
 
654
    Now adjust lock_position and lock_data_start for all objects that was
 
655
    moved in 'b' (as there is now all objects in 'a' before these).
 
656
  */
 
657
  for (table= sql_lock->table + a->table_count,
 
658
         end_table= table + b->table_count;
 
659
       table < end_table;
 
660
       table++)
 
661
  {
 
662
    (*table)->lock_position+=   a->table_count;
 
663
    (*table)->lock_data_start+= a->lock_count;
 
664
  }
 
665
 
 
666
  /* Delete old, not needed locks */
 
667
  my_free((uchar*) a,MYF(0));
 
668
  my_free((uchar*) b,MYF(0));
 
669
  DBUG_RETURN(sql_lock);
 
670
}
 
671
 
 
672
 
 
673
/**
 
674
  Find duplicate lock in tables.
 
675
 
 
676
  Temporary tables are ignored here like they are ignored in
 
677
  get_lock_data(). If we allow two opens on temporary tables later,
 
678
  both functions should be checked.
 
679
 
 
680
  @param thd                 The current thread.
 
681
  @param needle              The table to check for duplicate lock.
 
682
  @param haystack            The list of tables to search for the dup lock.
 
683
 
 
684
  @note
 
685
    This is mainly meant for MERGE tables in INSERT ... SELECT
 
686
    situations. The 'real', underlying tables can be found only after
 
687
    the MERGE tables are opened. This function assumes that the tables are
 
688
    already locked.
 
689
 
 
690
  @retval
 
691
    NULL    No duplicate lock found.
 
692
  @retval
 
693
    !NULL   First table from 'haystack' that matches a lock on 'needle'.
 
694
*/
 
695
 
 
696
TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
 
697
                                      TABLE_LIST *haystack)
 
698
{
 
699
  MYSQL_LOCK            *mylock;
 
700
  TABLE                 **lock_tables;
 
701
  TABLE                 *table;
 
702
  TABLE                 *table2;
 
703
  THR_LOCK_DATA         **lock_locks;
 
704
  THR_LOCK_DATA         **table_lock_data;
 
705
  THR_LOCK_DATA         **end_data;
 
706
  THR_LOCK_DATA         **lock_data2;
 
707
  THR_LOCK_DATA         **end_data2;
 
708
  DBUG_ENTER("mysql_lock_have_duplicate");
 
709
 
 
710
  /*
 
711
    Table may not be defined for derived or view tables.
 
712
    Table may not be part of a lock for delayed operations.
 
713
  */
 
714
  if (! (table= needle->table) || ! table->lock_count)
 
715
    goto end;
 
716
 
 
717
  /* A temporary table does not have locks. */
 
718
  if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
 
719
    goto end;
 
720
 
 
721
  /* Get command lock or LOCK TABLES lock. Maybe empty for INSERT DELAYED. */
 
722
  if (! (mylock= thd->lock ? thd->lock : thd->locked_tables))
 
723
    goto end;
 
724
 
 
725
  /* If we have less than two tables, we cannot have duplicates. */
 
726
  if (mylock->table_count < 2)
 
727
    goto end;
 
728
 
 
729
  lock_locks=  mylock->locks;
 
730
  lock_tables= mylock->table;
 
731
 
 
732
  /* Prepare table related variables that don't change in loop. */
 
733
  DBUG_ASSERT((table->lock_position < mylock->table_count) &&
 
734
              (table == lock_tables[table->lock_position]));
 
735
  table_lock_data= lock_locks + table->lock_data_start;
 
736
  end_data= table_lock_data + table->lock_count;
 
737
 
 
738
  for (; haystack; haystack= haystack->next_global)
 
739
  {
 
740
    if (haystack->placeholder())
 
741
      continue;
 
742
    table2= haystack->table;
 
743
    if (table2->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
 
744
      continue;
 
745
 
 
746
    /* All tables in list must be in lock. */
 
747
    DBUG_ASSERT((table2->lock_position < mylock->table_count) &&
 
748
                (table2 == lock_tables[table2->lock_position]));
 
749
 
 
750
    for (lock_data2=  lock_locks + table2->lock_data_start,
 
751
           end_data2= lock_data2 + table2->lock_count;
 
752
         lock_data2 < end_data2;
 
753
         lock_data2++)
 
754
    {
 
755
      THR_LOCK_DATA **lock_data;
 
756
      THR_LOCK *lock2= (*lock_data2)->lock;
 
757
 
 
758
      for (lock_data= table_lock_data;
 
759
           lock_data < end_data;
 
760
           lock_data++)
 
761
      {
 
762
        if ((*lock_data)->lock == lock2)
 
763
        {
 
764
          DBUG_PRINT("info", ("haystack match: '%s'", haystack->table_name));
 
765
          DBUG_RETURN(haystack);
 
766
        }
 
767
      }
 
768
    }
 
769
  }
 
770
 
 
771
 end:
 
772
  DBUG_PRINT("info", ("no duplicate found"));
 
773
  DBUG_RETURN(NULL);
 
774
}
 
775
 
 
776
 
 
777
/** Unlock a set of external. */
 
778
 
 
779
static int unlock_external(THD *thd, TABLE **table,uint count)
 
780
{
 
781
  int error,error_code;
 
782
  DBUG_ENTER("unlock_external");
 
783
 
 
784
  error_code=0;
 
785
  do
 
786
  {
 
787
    if ((*table)->current_lock != F_UNLCK)
 
788
    {
 
789
      (*table)->current_lock = F_UNLCK;
 
790
      if ((error=(*table)->file->ha_external_lock(thd, F_UNLCK)))
 
791
      {
 
792
        error_code=error;
 
793
        print_lock_error(error_code, (*table)->file->table_type());
 
794
      }
 
795
    }
 
796
    table++;
 
797
  } while (--count);
 
798
  DBUG_RETURN(error_code);
 
799
}
 
800
 
 
801
 
 
802
/**
 
803
  Get lock structures from table structs and initialize locks.
 
804
 
 
805
  @param thd                Thread handler
 
806
  @param table_ptr          Pointer to tables that should be locks
 
807
  @param flags              One of:
 
808
           - GET_LOCK_UNLOCK      : If we should send TL_IGNORE to store lock
 
809
           - GET_LOCK_STORE_LOCKS : Store lock info in TABLE
 
810
  @param write_lock_used   Store pointer to last table with WRITE_ALLOW_WRITE
 
811
*/
 
812
 
 
813
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
 
814
                                 uint flags, TABLE **write_lock_used)
 
815
{
 
816
  uint i,tables,lock_count;
 
817
  MYSQL_LOCK *sql_lock;
 
818
  THR_LOCK_DATA **locks, **locks_buf, **locks_start;
 
819
  TABLE **to, **table_buf;
 
820
  DBUG_ENTER("get_lock_data");
 
821
 
 
822
  DBUG_ASSERT((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
 
823
 
 
824
  DBUG_PRINT("info", ("count %d", count));
 
825
  *write_lock_used=0;
 
826
  for (i=tables=lock_count=0 ; i < count ; i++)
 
827
  {
 
828
    TABLE *t= table_ptr[i];
 
829
 
 
830
    if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
 
831
    {
 
832
      tables+= t->file->lock_count();
 
833
      lock_count++;
 
834
    }
 
835
  }
 
836
 
 
837
  /*
 
838
    Allocating twice the number of pointers for lock data for use in
 
839
    thr_mulit_lock(). This function reorders the lock data, but cannot
 
840
    update the table values. So the second part of the array is copied
 
841
    from the first part immediately before calling thr_multi_lock().
 
842
  */
 
843
  if (!(sql_lock= (MYSQL_LOCK*)
 
844
        my_malloc(sizeof(*sql_lock) +
 
845
                  sizeof(THR_LOCK_DATA*) * tables * 2 +
 
846
                  sizeof(table_ptr) * lock_count,
 
847
                  MYF(0))))
 
848
    DBUG_RETURN(0);
 
849
  locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
 
850
  to= table_buf= sql_lock->table= (TABLE**) (locks + tables * 2);
 
851
  sql_lock->table_count=lock_count;
 
852
 
 
853
  for (i=0 ; i < count ; i++)
 
854
  {
 
855
    TABLE *table;
 
856
    enum thr_lock_type lock_type;
 
857
 
 
858
    if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
 
859
      continue;
 
860
    lock_type= table->reginfo.lock_type;
 
861
    DBUG_ASSERT (lock_type != TL_WRITE_DEFAULT);
 
862
    if (lock_type >= TL_WRITE_ALLOW_WRITE)
 
863
    {
 
864
      *write_lock_used=table;
 
865
      if (table->db_stat & HA_READ_ONLY)
 
866
      {
 
867
        my_error(ER_OPEN_AS_READONLY,MYF(0),table->alias);
 
868
        /* Clear the lock type of the lock data that are stored already. */
 
869
        sql_lock->lock_count= locks - sql_lock->locks;
 
870
        reset_lock_data_and_free(&sql_lock);
 
871
        DBUG_RETURN(0);
 
872
      }
 
873
    }
 
874
    THR_LOCK_DATA **org_locks = locks;
 
875
    locks_start= locks;
 
876
    locks= table->file->store_lock(thd, locks,
 
877
                                   (flags & GET_LOCK_UNLOCK) ? TL_IGNORE :
 
878
                                   lock_type);
 
879
    if (flags & GET_LOCK_STORE_LOCKS)
 
880
    {
 
881
      table->lock_position=   (uint) (to - table_buf);
 
882
      table->lock_data_start= (uint) (locks_start - locks_buf);
 
883
      table->lock_count=      (uint) (locks - locks_start);
 
884
    }
 
885
    *to++= table;
 
886
    if (locks)
 
887
      for ( ; org_locks != locks ; org_locks++)
 
888
        (*org_locks)->debug_print_param= (void *) table;
 
889
  }
 
890
  /*
 
891
    We do not use 'tables', because there are cases where store_lock()
 
892
    returns less locks than lock_count() claimed. This can happen when
 
893
    a FLUSH TABLES tries to abort locks from a MERGE table of another
 
894
    thread. When that thread has just opened the table, but not yet
 
895
    attached its children, it cannot return the locks. lock_count()
 
896
    always returns the number of locks that an attached table has.
 
897
    This is done to avoid the reverse situation: If lock_count() would
 
898
    return 0 for a non-attached MERGE table, and that table becomes
 
899
    attached between the calls to lock_count() and store_lock(), then
 
900
    we would have allocated too little memory for the lock data. Now
 
901
    we may allocate too much, but better safe than memory overrun.
 
902
    And in the FLUSH case, the memory is released quickly anyway.
 
903
  */
 
904
  sql_lock->lock_count= locks - locks_buf;
 
905
  DBUG_PRINT("info", ("sql_lock->table_count %d sql_lock->lock_count %d",
 
906
                      sql_lock->table_count, sql_lock->lock_count));
 
907
  DBUG_RETURN(sql_lock);
 
908
}
 
909
 
 
910
 
 
911
/*****************************************************************************
 
912
  Lock table based on the name.
 
913
  This is used when we need total access to a closed, not open table
 
914
*****************************************************************************/
 
915
 
 
916
/**
 
917
  Lock and wait for the named lock.
 
918
 
 
919
  @param thd                    Thread handler
 
920
  @param table_list             Lock first table in this list
 
921
 
 
922
 
 
923
  @note
 
924
    Works together with global read lock.
 
925
 
 
926
  @retval
 
927
    0   ok
 
928
  @retval
 
929
    1   error
 
930
*/
 
931
 
 
932
int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list)
 
933
{
 
934
  int lock_retcode;
 
935
  int error= -1;
 
936
  DBUG_ENTER("lock_and_wait_for_table_name");
 
937
 
 
938
  if (wait_if_global_read_lock(thd, 0, 1))
 
939
    DBUG_RETURN(1);
 
940
  VOID(pthread_mutex_lock(&LOCK_open));
 
941
  if ((lock_retcode = lock_table_name(thd, table_list, TRUE)) < 0)
 
942
    goto end;
 
943
  if (lock_retcode && wait_for_locked_table_names(thd, table_list))
 
944
  {
 
945
    unlock_table_name(thd, table_list);
 
946
    goto end;
 
947
  }
 
948
  error=0;
 
949
 
 
950
end:
 
951
  pthread_mutex_unlock(&LOCK_open);
 
952
  start_waiting_global_read_lock(thd);
 
953
  DBUG_RETURN(error);
 
954
}
 
955
 
 
956
 
 
957
/**
 
958
  Put a not open table with an old refresh version in the table cache.
 
959
 
 
960
  @param thd                    Thread handler
 
961
  @param table_list             Lock first table in this list
 
962
  @param check_in_use           Do we need to check if table already in use by us
 
963
 
 
964
  @note
 
965
    One must have a lock on LOCK_open!
 
966
 
 
967
  @warning
 
968
    If you are going to update the table, you should use
 
969
    lock_and_wait_for_table_name instead of this function as this works
 
970
    together with 'FLUSH TABLES WITH READ LOCK'
 
971
 
 
972
  @note
 
973
    This will force any other threads that uses the table to release it
 
974
    as soon as possible.
 
975
 
 
976
  @return
 
977
    < 0 error
 
978
  @return
 
979
    == 0 table locked
 
980
  @return
 
981
    > 0  table locked, but someone is using it
 
982
*/
 
983
 
 
984
int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use)
 
985
{
 
986
  TABLE *table;
 
987
  char  key[MAX_DBKEY_LENGTH];
 
988
  char *db= table_list->db;
 
989
  uint  key_length;
 
990
  bool  found_locked_table= FALSE;
 
991
  HASH_SEARCH_STATE state;
 
992
  DBUG_ENTER("lock_table_name");
 
993
  DBUG_PRINT("enter",("db: %s  name: %s", db, table_list->table_name));
 
994
 
 
995
  key_length= create_table_def_key(thd, key, table_list, 0);
 
996
 
 
997
  if (check_in_use)
 
998
  {
 
999
    /* Only insert the table if we haven't insert it already */
 
1000
    for (table=(TABLE*) hash_first(&open_cache, (uchar*)key,
 
1001
                                   key_length, &state);
 
1002
         table ;
 
1003
         table = (TABLE*) hash_next(&open_cache,(uchar*) key,
 
1004
                                    key_length, &state))
 
1005
    {
 
1006
      if (table->reginfo.lock_type < TL_WRITE)
 
1007
      {
 
1008
        if (table->in_use == thd)
 
1009
          found_locked_table= TRUE;
 
1010
        continue;
 
1011
      }
 
1012
 
 
1013
      if (table->in_use == thd)
 
1014
      {
 
1015
        DBUG_PRINT("info", ("Table is in use"));
 
1016
        table->s->version= 0;                  // Ensure no one can use this
 
1017
        table->locked_by_name= 1;
 
1018
        DBUG_RETURN(0);
 
1019
      }
 
1020
    }
 
1021
  }
 
1022
 
 
1023
  if (thd->locked_tables && thd->locked_tables->table_count &&
 
1024
      ! find_temporary_table(thd, table_list->db, table_list->table_name))
 
1025
  {
 
1026
    if (found_locked_table)
 
1027
      my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias);
 
1028
    else
 
1029
      my_error(ER_TABLE_NOT_LOCKED, MYF(0), table_list->alias);
 
1030
 
 
1031
    DBUG_RETURN(-1);
 
1032
  }
 
1033
 
 
1034
  if (!(table= table_cache_insert_placeholder(thd, key, key_length)))
 
1035
    DBUG_RETURN(-1);
 
1036
 
 
1037
  table_list->table=table;
 
1038
 
 
1039
  /* Return 1 if table is in use */
 
1040
  DBUG_RETURN(test(remove_table_from_cache(thd, db, table_list->table_name,
 
1041
             check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
 
1042
}
 
1043
 
 
1044
 
 
1045
void unlock_table_name(THD *thd, TABLE_LIST *table_list)
 
1046
{
 
1047
  if (table_list->table)
 
1048
  {
 
1049
    hash_delete(&open_cache, (uchar*) table_list->table);
 
1050
    broadcast_refresh();
 
1051
  }
 
1052
}
 
1053
 
 
1054
 
 
1055
static bool locked_named_table(THD *thd, TABLE_LIST *table_list)
 
1056
{
 
1057
  for (; table_list ; table_list=table_list->next_local)
 
1058
  {
 
1059
    TABLE *table= table_list->table;
 
1060
    if (table)
 
1061
    {
 
1062
      TABLE *save_next= table->next;
 
1063
      bool result;
 
1064
      table->next= 0;
 
1065
      result= table_is_used(table_list->table, 0);
 
1066
      table->next= save_next;
 
1067
      if (result)
 
1068
        return 1;
 
1069
    }
 
1070
  }
 
1071
  return 0;                                     // All tables are locked
 
1072
}
 
1073
 
 
1074
 
 
1075
bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list)
 
1076
{
 
1077
  bool result=0;
 
1078
  DBUG_ENTER("wait_for_locked_table_names");
 
1079
 
 
1080
  safe_mutex_assert_owner(&LOCK_open);
 
1081
 
 
1082
  while (locked_named_table(thd,table_list))
 
1083
  {
 
1084
    if (thd->killed)
 
1085
    {
 
1086
      result=1;
 
1087
      break;
 
1088
    }
 
1089
    wait_for_condition(thd, &LOCK_open, &COND_refresh);
 
1090
    pthread_mutex_lock(&LOCK_open);
 
1091
  }
 
1092
  DBUG_RETURN(result);
 
1093
}
 
1094
 
 
1095
 
 
1096
/**
 
1097
  Lock all tables in list with a name lock.
 
1098
 
 
1099
  REQUIREMENTS
 
1100
  - One must have a lock on LOCK_open when calling this
 
1101
 
 
1102
  @param thd                    Thread handle
 
1103
  @param table_list             Names of tables to lock
 
1104
 
 
1105
  @note
 
1106
    If you are just locking one table, you should use
 
1107
    lock_and_wait_for_table_name().
 
1108
 
 
1109
  @retval
 
1110
    0   ok
 
1111
  @retval
 
1112
    1   Fatal error (end of memory ?)
 
1113
*/
 
1114
 
 
1115
bool lock_table_names(THD *thd, TABLE_LIST *table_list)
 
1116
{
 
1117
  bool got_all_locks=1;
 
1118
  TABLE_LIST *lock_table;
 
1119
 
 
1120
  for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
 
1121
  {
 
1122
    int got_lock;
 
1123
    if ((got_lock=lock_table_name(thd,lock_table, TRUE)) < 0)
 
1124
      goto end;                                 // Fatal error
 
1125
    if (got_lock)
 
1126
      got_all_locks=0;                          // Someone is using table
 
1127
  }
 
1128
 
 
1129
  /* If some table was in use, wait until we got the lock */
 
1130
  if (!got_all_locks && wait_for_locked_table_names(thd, table_list))
 
1131
    goto end;
 
1132
  return 0;
 
1133
 
 
1134
end:
 
1135
  unlock_table_names(thd, table_list, lock_table);
 
1136
  return 1;
 
1137
}
 
1138
 
 
1139
 
 
1140
/**
 
1141
  Unlock all tables in list with a name lock.
 
1142
 
 
1143
  @param thd        Thread handle.
 
1144
  @param table_list Names of tables to lock.
 
1145
 
 
1146
  @note 
 
1147
    This function needs to be protected by LOCK_open. If we're 
 
1148
    under LOCK TABLES, this function does not work as advertised. Namely,
 
1149
    it does not exclude other threads from using this table and does not
 
1150
    put an exclusive name lock on this table into the table cache.
 
1151
 
 
1152
  @see lock_table_names
 
1153
  @see unlock_table_names
 
1154
 
 
1155
  @retval TRUE An error occured.
 
1156
  @retval FALSE Name lock successfully acquired.
 
1157
*/
 
1158
 
 
1159
bool lock_table_names_exclusively(THD *thd, TABLE_LIST *table_list)
 
1160
{
 
1161
  if (lock_table_names(thd, table_list))
 
1162
    return TRUE;
 
1163
 
 
1164
  /*
 
1165
    Upgrade the table name locks from semi-exclusive to exclusive locks.
 
1166
  */
 
1167
  for (TABLE_LIST *table= table_list; table; table= table->next_global)
 
1168
  {
 
1169
    if (table->table)
 
1170
      table->table->open_placeholder= 1;
 
1171
  }
 
1172
  return FALSE;
 
1173
}
 
1174
 
 
1175
 
 
1176
/**
 
1177
  Test is 'table' is protected by an exclusive name lock.
 
1178
 
 
1179
  @param[in] thd        The current thread handler
 
1180
  @param[in] table_list Table container containing the single table to be
 
1181
                        tested
 
1182
 
 
1183
  @note Needs to be protected by LOCK_open mutex.
 
1184
 
 
1185
  @return Error status code
 
1186
    @retval TRUE Table is protected
 
1187
    @retval FALSE Table is not protected
 
1188
*/
 
1189
 
 
1190
bool
 
1191
is_table_name_exclusively_locked_by_this_thread(THD *thd,
 
1192
                                                TABLE_LIST *table_list)
 
1193
{
 
1194
  char  key[MAX_DBKEY_LENGTH];
 
1195
  uint  key_length;
 
1196
 
 
1197
  key_length= create_table_def_key(thd, key, table_list, 0);
 
1198
 
 
1199
  return is_table_name_exclusively_locked_by_this_thread(thd, (uchar *)key,
 
1200
                                                         key_length);
 
1201
}
 
1202
 
 
1203
 
 
1204
/**
 
1205
  Test is 'table key' is protected by an exclusive name lock.
 
1206
 
 
1207
  @param[in] thd        The current thread handler.
 
1208
  @param[in] key
 
1209
  @param[in] key_length
 
1210
 
 
1211
  @note Needs to be protected by LOCK_open mutex
 
1212
 
 
1213
  @retval TRUE Table is protected
 
1214
  @retval FALSE Table is not protected
 
1215
 */
 
1216
 
 
1217
bool
 
1218
is_table_name_exclusively_locked_by_this_thread(THD *thd, uchar *key,
 
1219
                                                int key_length)
 
1220
{
 
1221
  HASH_SEARCH_STATE state;
 
1222
  TABLE *table;
 
1223
 
 
1224
  for (table= (TABLE*) hash_first(&open_cache, key,
 
1225
                                  key_length, &state);
 
1226
       table ;
 
1227
       table= (TABLE*) hash_next(&open_cache, key,
 
1228
                                 key_length, &state))
 
1229
  {
 
1230
    if (table->in_use == thd &&
 
1231
        table->open_placeholder == 1 &&
 
1232
        table->s->version == 0)
 
1233
      return TRUE;
 
1234
  }
 
1235
 
 
1236
  return FALSE;
 
1237
}
 
1238
 
 
1239
/**
 
1240
  Unlock all tables in list with a name lock.
 
1241
 
 
1242
  @param
 
1243
    thd                 Thread handle
 
1244
  @param
 
1245
    table_list          Names of tables to unlock
 
1246
  @param
 
1247
    last_table          Don't unlock any tables after this one.
 
1248
                                (default 0, which will unlock all tables)
 
1249
 
 
1250
  @note
 
1251
    One must have a lock on LOCK_open when calling this.
 
1252
 
 
1253
  @note
 
1254
    This function will broadcast refresh signals to inform other threads
 
1255
    that the name locks are removed.
 
1256
 
 
1257
  @retval
 
1258
    0   ok
 
1259
  @retval
 
1260
    1   Fatal error (end of memory ?)
 
1261
*/
 
1262
 
 
1263
void unlock_table_names(THD *thd, TABLE_LIST *table_list,
 
1264
                        TABLE_LIST *last_table)
 
1265
{
 
1266
  DBUG_ENTER("unlock_table_names");
 
1267
  for (TABLE_LIST *table= table_list;
 
1268
       table != last_table;
 
1269
       table= table->next_local)
 
1270
    unlock_table_name(thd,table);
 
1271
  broadcast_refresh();
 
1272
  DBUG_VOID_RETURN;
 
1273
}
 
1274
 
 
1275
 
 
1276
static void print_lock_error(int error, const char *table)
 
1277
{
 
1278
  int textno;
 
1279
  DBUG_ENTER("print_lock_error");
 
1280
 
 
1281
  switch (error) {
 
1282
  case HA_ERR_LOCK_WAIT_TIMEOUT:
 
1283
    textno=ER_LOCK_WAIT_TIMEOUT;
 
1284
    break;
 
1285
  case HA_ERR_READ_ONLY_TRANSACTION:
 
1286
    textno=ER_READ_ONLY_TRANSACTION;
 
1287
    break;
 
1288
  case HA_ERR_LOCK_DEADLOCK:
 
1289
    textno=ER_LOCK_DEADLOCK;
 
1290
    break;
 
1291
  case HA_ERR_WRONG_COMMAND:
 
1292
    textno=ER_ILLEGAL_HA;
 
1293
    break;
 
1294
  default:
 
1295
    textno=ER_CANT_LOCK;
 
1296
    break;
 
1297
  }
 
1298
 
 
1299
  if ( textno == ER_ILLEGAL_HA )
 
1300
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
 
1301
  else
 
1302
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
 
1303
 
 
1304
  DBUG_VOID_RETURN;
 
1305
}
 
1306
 
 
1307
 
 
1308
/****************************************************************************
 
1309
  Handling of global read locks
 
1310
 
 
1311
  Taking the global read lock is TWO steps (2nd step is optional; without
 
1312
  it, COMMIT of existing transactions will be allowed):
 
1313
  lock_global_read_lock() THEN make_global_read_lock_block_commit().
 
1314
 
 
1315
  The global locks are handled through the global variables:
 
1316
  global_read_lock
 
1317
    count of threads which have the global read lock (i.e. have completed at
 
1318
    least the first step above)
 
1319
  global_read_lock_blocks_commit
 
1320
    count of threads which have the global read lock and block
 
1321
    commits (i.e. are in or have completed the second step above)
 
1322
  waiting_for_read_lock
 
1323
    count of threads which want to take a global read lock but cannot
 
1324
  protect_against_global_read_lock
 
1325
    count of threads which have set protection against global read lock.
 
1326
 
 
1327
  access to them is protected with a mutex LOCK_global_read_lock
 
1328
 
 
1329
  (XXX: one should never take LOCK_open if LOCK_global_read_lock is
 
1330
  taken, otherwise a deadlock may occur. Other mutexes could be a
 
1331
  problem too - grep the code for global_read_lock if you want to use
 
1332
  any other mutex here) Also one must not hold LOCK_open when calling
 
1333
  wait_if_global_read_lock(). When the thread with the global read lock
 
1334
  tries to close its tables, it needs to take LOCK_open in
 
1335
  close_thread_table().
 
1336
 
 
1337
  How blocking of threads by global read lock is achieved: that's
 
1338
  advisory. Any piece of code which should be blocked by global read lock must
 
1339
  be designed like this:
 
1340
  - call to wait_if_global_read_lock(). When this returns 0, no global read
 
1341
  lock is owned; if argument abort_on_refresh was 0, none can be obtained.
 
1342
  - job
 
1343
  - if abort_on_refresh was 0, call to start_waiting_global_read_lock() to
 
1344
  allow other threads to get the global read lock. I.e. removal of the
 
1345
  protection.
 
1346
  (Note: it's a bit like an implementation of rwlock).
 
1347
 
 
1348
  [ I am sorry to mention some SQL syntaxes below I know I shouldn't but found
 
1349
  no better descriptive way ]
 
1350
 
 
1351
  Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used
 
1352
  to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary
 
1353
  log.
 
1354
 
 
1355
  Why getting the global read lock is two steps and not one. Because FLUSH
 
1356
  TABLES WITH READ LOCK needs to insert one other step between the two:
 
1357
  flushing tables. So the order is
 
1358
  1) lock_global_read_lock() (prevents any new table write locks, i.e. stalls
 
1359
  all new updates)
 
1360
  2) close_cached_tables() (the FLUSH TABLES), which will wait for tables
 
1361
  currently opened and being updated to close (so it's possible that there is
 
1362
  a moment where all new updates of server are stalled *and* FLUSH TABLES WITH
 
1363
  READ LOCK is, too).
 
1364
  3) make_global_read_lock_block_commit().
 
1365
  If we have merged 1) and 3) into 1), we would have had this deadlock:
 
1366
  imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
 
1367
  table t.
 
1368
  thd1: SELECT * FROM t FOR UPDATE;
 
1369
  thd2: UPDATE t SET a=1; # blocked by row-level locks of thd1
 
1370
  thd3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
 
1371
  table instance of thd2
 
1372
  thd1: COMMIT; # blocked by thd3.
 
1373
  thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock.
 
1374
 
 
1375
  Note that we need to support that one thread does
 
1376
  FLUSH TABLES WITH READ LOCK; and then COMMIT;
 
1377
  (that's what innobackup does, for some good reason).
 
1378
  So in this exceptional case the COMMIT should not be blocked by the FLUSH
 
1379
  TABLES WITH READ LOCK.
 
1380
 
 
1381
****************************************************************************/
 
1382
 
 
1383
volatile uint global_read_lock=0;
 
1384
volatile uint global_read_lock_blocks_commit=0;
 
1385
static volatile uint protect_against_global_read_lock=0;
 
1386
static volatile uint waiting_for_read_lock=0;
 
1387
 
 
1388
#define GOT_GLOBAL_READ_LOCK               1
 
1389
#define MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT 2
 
1390
 
 
1391
bool lock_global_read_lock(THD *thd)
 
1392
{
 
1393
  DBUG_ENTER("lock_global_read_lock");
 
1394
 
 
1395
  if (!thd->global_read_lock)
 
1396
  {
 
1397
    const char *old_message;
 
1398
    (void) pthread_mutex_lock(&LOCK_global_read_lock);
 
1399
    old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
 
1400
                                "Waiting to get readlock");
 
1401
    DBUG_PRINT("info",
 
1402
               ("waiting_for: %d  protect_against: %d",
 
1403
                waiting_for_read_lock, protect_against_global_read_lock));
 
1404
 
 
1405
    waiting_for_read_lock++;
 
1406
    while (protect_against_global_read_lock && !thd->killed)
 
1407
      pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
 
1408
    waiting_for_read_lock--;
 
1409
    if (thd->killed)
 
1410
    {
 
1411
      thd->exit_cond(old_message);
 
1412
      DBUG_RETURN(1);
 
1413
    }
 
1414
    thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
 
1415
    global_read_lock++;
 
1416
    thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1417
  }
 
1418
  /*
 
1419
    We DON'T set global_read_lock_blocks_commit now, it will be set after
 
1420
    tables are flushed (as the present function serves for FLUSH TABLES WITH
 
1421
    READ LOCK only). Doing things in this order is necessary to avoid
 
1422
    deadlocks (we must allow COMMIT until all tables are closed; we should not
 
1423
    forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
 
1424
    UPDATE and one does FLUSH TABLES WITH READ LOCK).
 
1425
  */
 
1426
  DBUG_RETURN(0);
 
1427
}
 
1428
 
 
1429
 
 
1430
void unlock_global_read_lock(THD *thd)
 
1431
{
 
1432
  uint tmp;
 
1433
  DBUG_ENTER("unlock_global_read_lock");
 
1434
  DBUG_PRINT("info",
 
1435
             ("global_read_lock: %u  global_read_lock_blocks_commit: %u",
 
1436
              global_read_lock, global_read_lock_blocks_commit));
 
1437
 
 
1438
  pthread_mutex_lock(&LOCK_global_read_lock);
 
1439
  tmp= --global_read_lock;
 
1440
  if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
 
1441
    --global_read_lock_blocks_commit;
 
1442
  pthread_mutex_unlock(&LOCK_global_read_lock);
 
1443
  /* Send the signal outside the mutex to avoid a context switch */
 
1444
  if (!tmp)
 
1445
  {
 
1446
    DBUG_PRINT("signal", ("Broadcasting COND_global_read_lock"));
 
1447
    pthread_cond_broadcast(&COND_global_read_lock);
 
1448
  }
 
1449
  thd->global_read_lock= 0;
 
1450
 
 
1451
  DBUG_VOID_RETURN;
 
1452
}
 
1453
 
 
1454
#define must_wait (global_read_lock &&                             \
 
1455
                   (is_not_commit ||                               \
 
1456
                    global_read_lock_blocks_commit))
 
1457
 
 
1458
bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
 
1459
                              bool is_not_commit)
 
1460
{
 
1461
  const char *old_message= NULL;
 
1462
  bool result= 0, need_exit_cond;
 
1463
  DBUG_ENTER("wait_if_global_read_lock");
 
1464
 
 
1465
  /*
 
1466
    Assert that we do not own LOCK_open. If we would own it, other
 
1467
    threads could not close their tables. This would make a pretty
 
1468
    deadlock.
 
1469
  */
 
1470
  safe_mutex_assert_not_owner(&LOCK_open);
 
1471
 
 
1472
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
 
1473
  if ((need_exit_cond= must_wait))
 
1474
  {
 
1475
    if (thd->global_read_lock)          // This thread had the read locks
 
1476
    {
 
1477
      if (is_not_commit)
 
1478
        my_message(ER_CANT_UPDATE_WITH_READLOCK,
 
1479
                   ER(ER_CANT_UPDATE_WITH_READLOCK), MYF(0));
 
1480
      (void) pthread_mutex_unlock(&LOCK_global_read_lock);
 
1481
      /*
 
1482
        We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
 
1483
        This allowance is needed to not break existing versions of innobackup
 
1484
        which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT.
 
1485
      */
 
1486
      DBUG_RETURN(is_not_commit);
 
1487
    }
 
1488
    old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
 
1489
                                "Waiting for release of readlock");
 
1490
    while (must_wait && ! thd->killed &&
 
1491
           (!abort_on_refresh || thd->version == refresh_version))
 
1492
    {
 
1493
      DBUG_PRINT("signal", ("Waiting for COND_global_read_lock"));
 
1494
      (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
 
1495
      DBUG_PRINT("signal", ("Got COND_global_read_lock"));
 
1496
    }
 
1497
    if (thd->killed)
 
1498
      result=1;
 
1499
  }
 
1500
  if (!abort_on_refresh && !result)
 
1501
    protect_against_global_read_lock++;
 
1502
  /*
 
1503
    The following is only true in case of a global read locks (which is rare)
 
1504
    and if old_message is set
 
1505
  */
 
1506
  if (unlikely(need_exit_cond))
 
1507
    thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1508
  else
 
1509
    pthread_mutex_unlock(&LOCK_global_read_lock);
 
1510
  DBUG_RETURN(result);
 
1511
}
 
1512
 
 
1513
 
 
1514
void start_waiting_global_read_lock(THD *thd)
 
1515
{
 
1516
  bool tmp;
 
1517
  DBUG_ENTER("start_waiting_global_read_lock");
 
1518
  if (unlikely(thd->global_read_lock))
 
1519
    DBUG_VOID_RETURN;
 
1520
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
 
1521
  tmp= (!--protect_against_global_read_lock &&
 
1522
        (waiting_for_read_lock || global_read_lock_blocks_commit));
 
1523
  (void) pthread_mutex_unlock(&LOCK_global_read_lock);
 
1524
  if (tmp)
 
1525
    pthread_cond_broadcast(&COND_global_read_lock);
 
1526
  DBUG_VOID_RETURN;
 
1527
}
 
1528
 
 
1529
 
 
1530
bool make_global_read_lock_block_commit(THD *thd)
 
1531
{
 
1532
  bool error;
 
1533
  const char *old_message;
 
1534
  DBUG_ENTER("make_global_read_lock_block_commit");
 
1535
  /*
 
1536
    If we didn't succeed lock_global_read_lock(), or if we already suceeded
 
1537
    make_global_read_lock_block_commit(), do nothing.
 
1538
  */
 
1539
  if (thd->global_read_lock != GOT_GLOBAL_READ_LOCK)
 
1540
    DBUG_RETURN(0);
 
1541
  pthread_mutex_lock(&LOCK_global_read_lock);
 
1542
  /* increment this BEFORE waiting on cond (otherwise race cond) */
 
1543
  global_read_lock_blocks_commit++;
 
1544
  /* For testing we set up some blocking, to see if we can be killed */
 
1545
  DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
 
1546
                  protect_against_global_read_lock++;);
 
1547
  old_message= thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
 
1548
                               "Waiting for all running commits to finish");
 
1549
  while (protect_against_global_read_lock && !thd->killed)
 
1550
    pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
 
1551
  DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
 
1552
                  protect_against_global_read_lock--;);
 
1553
  if ((error= test(thd->killed)))
 
1554
    global_read_lock_blocks_commit--; // undo what we did
 
1555
  else
 
1556
    thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
 
1557
  thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
 
1558
  DBUG_RETURN(error);
 
1559
}
 
1560
 
 
1561
 
 
1562
/**
 
1563
  Broadcast COND_refresh and COND_global_read_lock.
 
1564
 
 
1565
    Due to a bug in a threading library it could happen that a signal
 
1566
    did not reach its target. A condition for this was that the same
 
1567
    condition variable was used with different mutexes in
 
1568
    pthread_cond_wait(). Some time ago we changed LOCK_open to
 
1569
    LOCK_global_read_lock in global read lock handling. So COND_refresh
 
1570
    was used with LOCK_open and LOCK_global_read_lock.
 
1571
 
 
1572
    We did now also change from COND_refresh to COND_global_read_lock
 
1573
    in global read lock handling. But now it is necessary to signal
 
1574
    both conditions at the same time.
 
1575
 
 
1576
  @note
 
1577
    When signalling COND_global_read_lock within the global read lock
 
1578
    handling, it is not necessary to also signal COND_refresh.
 
1579
*/
 
1580
 
 
1581
void broadcast_refresh(void)
 
1582
{
 
1583
  VOID(pthread_cond_broadcast(&COND_refresh));
 
1584
  VOID(pthread_cond_broadcast(&COND_global_read_lock));
 
1585
}
 
1586
 
 
1587
 
 
1588
/*
 
1589
  Try to get transactional table locks for the tables in the list.
 
1590
 
 
1591
  SYNOPSIS
 
1592
    try_transactional_lock()
 
1593
      thd                       Thread handle
 
1594
      table_list                List of tables to lock
 
1595
 
 
1596
  DESCRIPTION
 
1597
    This is called if transactional table locks are requested for all
 
1598
    tables in table_list and no non-transactional locks pre-exist.
 
1599
 
 
1600
  RETURN
 
1601
    0                   OK. All tables are transactional locked.
 
1602
    1                   Error: must fall back to non-transactional locks.
 
1603
    -1                  Error: no recovery possible.
 
1604
*/
 
1605
 
 
1606
int try_transactional_lock(THD *thd, TABLE_LIST *table_list)
 
1607
{
 
1608
  uint          dummy_counter;
 
1609
  int           error;
 
1610
  int           result= 0;
 
1611
  DBUG_ENTER("try_transactional_lock");
 
1612
 
 
1613
  /* Need to open the tables to be able to access engine methods. */
 
1614
  if (open_tables(thd, &table_list, &dummy_counter, 0))
 
1615
  {
 
1616
    /* purecov: begin tested */
 
1617
    DBUG_PRINT("lock_info", ("aborting, open_tables failed"));
 
1618
    DBUG_RETURN(-1);
 
1619
    /* purecov: end */
 
1620
  }
 
1621
 
 
1622
  /* Required by InnoDB. */
 
1623
  thd->in_lock_tables= TRUE;
 
1624
 
 
1625
  if ((error= set_handler_table_locks(thd, table_list, TRUE)))
 
1626
  {
 
1627
    /*
 
1628
      Not all transactional locks could be taken. If the error was
 
1629
      something else but "unsupported by storage engine", abort the
 
1630
      execution of this statement.
 
1631
    */
 
1632
    if (error != HA_ERR_WRONG_COMMAND)
 
1633
    {
 
1634
      DBUG_PRINT("lock_info", ("aborting, lock_table failed"));
 
1635
      result= -1;
 
1636
      goto err;
 
1637
    }
 
1638
    /*
 
1639
      Fall back to non-transactional locks because transactional locks
 
1640
      are unsupported by a storage engine. No need to unlock the
 
1641
      successfully taken transactional locks. They go away at end of
 
1642
      transaction anyway.
 
1643
    */
 
1644
    DBUG_PRINT("lock_info", ("fall back to non-trans lock: no SE support"));
 
1645
    result= 1;
 
1646
  }
 
1647
 
 
1648
 err:
 
1649
  /* We need to explicitly commit if autocommit mode is active. */
 
1650
  (void) ha_autocommit_or_rollback(thd, 0);
 
1651
  /* Close the tables. The locks (if taken) persist in the storage engines. */
 
1652
  close_tables_for_reopen(thd, &table_list);
 
1653
  thd->in_lock_tables= FALSE;
 
1654
  DBUG_PRINT("lock_info", ("result: %d", result));
 
1655
  DBUG_RETURN(result);
 
1656
}
 
1657
 
 
1658
 
 
1659
/*
 
1660
  Check if lock method conversion was done and was allowed.
 
1661
 
 
1662
  SYNOPSIS
 
1663
    check_transactional_lock()
 
1664
      thd                       Thread handle
 
1665
      table_list                List of tables to lock
 
1666
 
 
1667
  DESCRIPTION
 
1668
 
 
1669
    Lock method conversion can be done during parsing if one of the
 
1670
    locks is non-transactional. It can also happen if non-transactional
 
1671
    table locks exist when the statement is executed or if a storage
 
1672
    engine does not support transactional table locks.
 
1673
 
 
1674
    Check if transactional table locks have been converted to
 
1675
    non-transactional and if this was allowed. In a running transaction
 
1676
    or in strict mode lock method conversion is not allowed - report an
 
1677
    error. Otherwise it is allowed - issue a warning.
 
1678
 
 
1679
  RETURN
 
1680
    0                   OK. Proceed with non-transactional locks.
 
1681
    -1                  Error: Lock conversion is prohibited.
 
1682
*/
 
1683
 
 
1684
int check_transactional_lock(THD *thd, TABLE_LIST *table_list)
 
1685
{
 
1686
  TABLE_LIST    *tlist;
 
1687
  int           result= 0;
 
1688
  char          warn_buff[MYSQL_ERRMSG_SIZE];
 
1689
  DBUG_ENTER("check_transactional_lock");
 
1690
 
 
1691
  for (tlist= table_list; tlist; tlist= tlist->next_global)
 
1692
  {
 
1693
    DBUG_PRINT("lock_info", ("checking table: '%s'", tlist->table_name));
 
1694
 
 
1695
    /*
 
1696
      Unfortunately we cannot use tlist->placeholder() here. This method
 
1697
      returns TRUE if the table is not open, which is always the case
 
1698
      here. Whenever the definition of TABLE_LIST::placeholder() is
 
1699
      changed, probably this condition needs to be changed too.
 
1700
    */
 
1701
    if (tlist->derived || tlist->schema_table || !tlist->lock_transactional)
 
1702
    {
 
1703
      DBUG_PRINT("lock_info", ("skipping placeholder: %d  transactional: %d",
 
1704
                               tlist->placeholder(),
 
1705
                               tlist->lock_transactional));
 
1706
      continue;
 
1707
    }
 
1708
 
 
1709
    /* We must not convert the lock method in strict mode. */
 
1710
    {
 
1711
      my_error(ER_NO_AUTO_CONVERT_LOCK_STRICT, MYF(0),
 
1712
               tlist->alias ? tlist->alias : tlist->table_name);
 
1713
      result= -1;
 
1714
      continue;
 
1715
    }
 
1716
 
 
1717
    /* We must not convert the lock method within an active transaction. */
 
1718
    if (thd->active_transaction())
 
1719
    {
 
1720
      my_error(ER_NO_AUTO_CONVERT_LOCK_TRANSACTION, MYF(0),
 
1721
               tlist->alias ? tlist->alias : tlist->table_name);
 
1722
      result= -1;
 
1723
      continue;
 
1724
    }
 
1725
 
 
1726
    /* Warn about the conversion. */
 
1727
    my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK),
 
1728
                tlist->alias ? tlist->alias : tlist->table_name);
 
1729
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
 
1730
                 ER_WARN_AUTO_CONVERT_LOCK, warn_buff);
 
1731
  }
 
1732
 
 
1733
  DBUG_PRINT("lock_info", ("result: %d", result));
 
1734
  DBUG_RETURN(result);
 
1735
}
 
1736
 
 
1737
 
 
1738
/*
 
1739
  Set table locks in the table handler.
 
1740
 
 
1741
  SYNOPSIS
 
1742
    set_handler_table_locks()
 
1743
      thd                       Thread handle
 
1744
      table_list                List of tables to lock
 
1745
      transactional             If to lock transactional or non-transactional
 
1746
 
 
1747
  RETURN
 
1748
    0                   OK.
 
1749
    != 0                Error code from handler::lock_table().
 
1750
*/
 
1751
 
 
1752
int set_handler_table_locks(THD *thd, TABLE_LIST *table_list,
 
1753
                            bool transactional)
 
1754
{
 
1755
  TABLE_LIST    *tlist;
 
1756
  int           error= 0;
 
1757
  DBUG_ENTER("set_handler_table_locks");
 
1758
  DBUG_PRINT("lock_info", ("transactional: %d", transactional));
 
1759
 
 
1760
  for (tlist= table_list; tlist; tlist= tlist->next_global)
 
1761
  {
 
1762
    int lock_type;
 
1763
    int lock_timeout= -1; /* Use default for non-transactional locks. */
 
1764
 
 
1765
    if (tlist->placeholder())
 
1766
      continue;
 
1767
 
 
1768
    DBUG_ASSERT((tlist->lock_type == TL_READ) ||
 
1769
                (tlist->lock_type == TL_READ_NO_INSERT) ||
 
1770
                (tlist->lock_type == TL_WRITE_DEFAULT) ||
 
1771
                (tlist->lock_type == TL_WRITE) ||
 
1772
                (tlist->lock_type == TL_WRITE_LOW_PRIORITY));
 
1773
 
 
1774
    /*
 
1775
      Every tlist object has a proper lock_type set. Even if it came in
 
1776
      the list as a base table from a view only.
 
1777
    */
 
1778
    lock_type= ((tlist->lock_type <= TL_READ_NO_INSERT) ?
 
1779
                HA_LOCK_IN_SHARE_MODE : HA_LOCK_IN_EXCLUSIVE_MODE);
 
1780
 
 
1781
    if (transactional)
 
1782
    {
 
1783
      /*
 
1784
        The lock timeout is not set if this table belongs to a view. We
 
1785
        need to take it from the top-level view. After this loop
 
1786
        iteration, lock_timeout is not needed any more. Not even if the
 
1787
        locks are converted to non-transactional locks later.
 
1788
        Non-transactional locks do not support a lock_timeout.
 
1789
      */
 
1790
      lock_timeout= tlist->top_table()->lock_timeout;
 
1791
      DBUG_PRINT("lock_info",
 
1792
                 ("table: '%s'  tlist==top_table: %d  lock_timeout: %d",
 
1793
                  tlist->table_name, tlist==tlist->top_table(), lock_timeout));
 
1794
 
 
1795
      /*
 
1796
        For warning/error reporting we need to set the intended lock
 
1797
        method in the TABLE_LIST object. It will be used later by
 
1798
        check_transactional_lock(). The lock method is not set if this
 
1799
        table belongs to a view. We can safely set it to transactional
 
1800
        locking here. Even for non-view tables. This function is not
 
1801
        called if non-transactional locking was requested for any
 
1802
        object.
 
1803
      */
 
1804
      tlist->lock_transactional= TRUE;
 
1805
    }
 
1806
 
 
1807
    /*
 
1808
      Because we need to set the lock method (see above) for all
 
1809
      involved tables, we cannot break the loop on an error.
 
1810
      But we do not try more locks after the first error.
 
1811
      However, for non-transactional locking handler::lock_table() is
 
1812
      a hint only. So we continue to call it for other tables.
 
1813
    */
 
1814
    if (!error || !transactional)
 
1815
    {
 
1816
      error= tlist->table->file->lock_table(thd, lock_type, lock_timeout);
 
1817
      if (error && transactional && (error != HA_ERR_WRONG_COMMAND))
 
1818
        tlist->table->file->print_error(error, MYF(0));
 
1819
    }
 
1820
  }
 
1821
 
 
1822
  DBUG_RETURN(error);
 
1823
}
 
1824
 
 
1825
 
 
1826
/**
 
1827
  @} (end of group Locking)
 
1828
*/