~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/lock.cc

  • Committer: Monty Taylor
  • Date: 2008-11-16 23:47:43 UTC
  • mto: (584.1.10 devel)
  • mto: This revision was merged to the branch mainline in revision 589.
  • Revision ID: monty@inaugust.com-20081116234743-c38gmv0pa2kdefaj
BrokeĀ outĀ cached_item.

Show diffs side-by-side

added added

removed removed

Lines of Context:
69
69
  in case external_lock() fails.
70
70
 
71
71
  @todo
72
 
  Change to use malloc() ONLY when using LOCK TABLES command or when
 
72
  Change to use my_malloc() ONLY when using LOCK TABLES command or when
73
73
  we are forced to use mysql_lock_merge.
74
74
*/
75
 
#include "config.h"
76
 
#include <fcntl.h>
 
75
#include <drizzled/server_includes.h>
77
76
#include <drizzled/error.h>
78
 
#include <drizzled/my_hash.h>
79
 
#include <drizzled/thr_lock.h>
80
 
#include <drizzled/session.h>
81
 
#include <drizzled/sql_base.h>
82
 
#include <drizzled/lock.h>
83
 
#include "drizzled/pthread_globals.h"
84
 
#include "drizzled/internal/my_sys.h"
85
 
 
86
 
#include <set>
87
 
#include <vector>
88
 
#include <algorithm>
89
 
#include <functional>
90
 
 
91
 
using namespace std;
92
 
 
93
 
namespace drizzled
94
 
{
95
77
 
96
78
/**
97
79
  @defgroup Locking Locking
100
82
 
101
83
extern HASH open_cache;
102
84
 
103
 
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table,
104
 
                                   uint32_t count,
105
 
                                   bool should_lock, Table **write_locked);
 
85
/* flags for get_lock_data */
 
86
#define GET_LOCK_UNLOCK         1
 
87
#define GET_LOCK_STORE_LOCKS    2
 
88
 
 
89
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table,uint32_t count,
 
90
                                 uint32_t flags, Table **write_locked);
106
91
static int lock_external(Session *session, Table **table,uint32_t count);
107
92
static int unlock_external(Session *session, Table **table,uint32_t count);
108
93
static void print_lock_error(int error, const char *);
117
102
    count                       The number of tables to lock.
118
103
    flags                       Options:
119
104
      DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK      Ignore a global read lock
 
105
      DRIZZLE_LOCK_IGNORE_GLOBAL_READ_ONLY      Ignore SET GLOBAL READ_ONLY
120
106
      DRIZZLE_LOCK_IGNORE_FLUSH                 Ignore a flush tables.
121
107
      DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN        Instead of reopening altered
122
108
                                              or dropped tables by itself,
175
161
 
176
162
 
177
163
DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
178
 
                                uint32_t flags, bool *need_reopen)
 
164
                              uint32_t flags, bool *need_reopen)
179
165
{
180
166
  DRIZZLE_LOCK *sql_lock;
181
167
  Table *write_lock_used;
182
 
  vector<plugin::StorageEngine *> involved_engines;
183
168
  int rc;
184
169
 
185
170
  *need_reopen= false;
186
171
 
187
172
  for (;;)
188
173
  {
189
 
    if (! (sql_lock= get_lock_data(session, tables, count, true,
 
174
    if (! (sql_lock= get_lock_data(session, tables, count, GET_LOCK_STORE_LOCKS,
190
175
                                   &write_lock_used)))
191
176
      break;
192
177
 
210
195
        goto retry;
211
196
      }
212
197
    }
213
 
    
214
 
    session->set_proc_info("Notify start statement");
215
 
    /*
216
 
     * Here, we advise all storage engines involved in the
217
 
     * statement that we are starting a new statement
218
 
     */
219
 
    if (sql_lock->table_count)
 
198
 
 
199
    if (!(flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_ONLY) &&
 
200
        write_lock_used &&
 
201
        opt_readonly &&
 
202
        !session->slave_thread)
220
203
    {
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++)
225
 
      {
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());
231
 
      }
232
 
 
233
 
      for_each(involved_engines.begin(),
234
 
               involved_engines.end(),
235
 
               bind2nd(mem_fun(&plugin::StorageEngine::startStatement), session));
 
204
      /*
 
205
        Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock.
 
206
        We do not wait for READ_ONLY=0, and fail.
 
207
      */
 
208
      reset_lock_data_and_free(&sql_lock);
 
209
      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
 
210
      break;
236
211
    }
237
212
 
238
 
    session->set_proc_info("External lock");
239
 
    /*
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 
243
 
     * specific table.
244
 
     */
 
213
    session->set_proc_info("System lock");
245
214
    if (sql_lock->table_count && lock_external(session, sql_lock->table,
246
215
                                               sql_lock->table_count))
247
216
    {
283
252
    else if (!session->open_tables)
284
253
    {
285
254
      // Only using temporary tables, no need to unlock
286
 
      session->some_tables_deleted= 0;
 
255
      session->some_tables_deleted=0;
287
256
      break;
288
257
    }
289
258
    session->set_proc_info(0);
301
270
      type for other tables preserved.
302
271
    */
303
272
    reset_lock_data_and_free(&sql_lock);
304
 
 
305
 
    /*
306
 
     * Notify all involved engines that the
307
 
     * SQL statement has ended
308
 
     */
309
 
    for_each(involved_engines.begin(),
310
 
             involved_engines.end(),
311
 
             bind2nd(mem_fun(&plugin::StorageEngine::endStatement), session));
312
273
retry:
313
274
    if (flags & DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN)
314
275
    {
325
286
    if (sql_lock)
326
287
    {
327
288
      mysql_unlock_tables(session,sql_lock);
328
 
      sql_lock= NULL;
 
289
      sql_lock=0;
329
290
    }
330
291
  }
 
292
 
331
293
  session->set_time_after_lock();
332
294
  return (sql_lock);
333
295
}
346
308
         (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
347
309
      lock_type=F_RDLCK;
348
310
 
349
 
    if ((error=(*tables)->cursor->ha_external_lock(session,lock_type)))
 
311
    if ((error=(*tables)->file->ha_external_lock(session,lock_type)))
350
312
    {
351
 
      print_lock_error(error, (*tables)->cursor->engine->getName().c_str());
 
313
      print_lock_error(error, (*tables)->file->table_type());
352
314
      while (--i)
353
315
      {
354
316
        tables--;
355
 
        (*tables)->cursor->ha_external_lock(session, F_UNLCK);
 
317
        (*tables)->file->ha_external_lock(session, F_UNLCK);
356
318
        (*tables)->current_lock=F_UNLCK;
357
319
      }
358
 
      return error;
 
320
      return(error);
359
321
    }
360
322
    else
361
323
    {
363
325
      (*tables)->current_lock= lock_type;
364
326
    }
365
327
  }
366
 
  return 0;
 
328
  return(0);
367
329
}
368
330
 
369
331
 
383
345
  This will work even if get_lock_data fails (next unlock will free all)
384
346
*/
385
347
 
386
 
void mysql_unlock_some_tables(Session *session, Table **table, uint32_t count)
 
348
void mysql_unlock_some_tables(Session *session, Table **table,uint32_t count)
387
349
{
388
350
  DRIZZLE_LOCK *sql_lock;
389
351
  Table *write_lock_used;
390
 
  if ((sql_lock= get_lock_data(session, table, count, false,
 
352
  if ((sql_lock= get_lock_data(session, table, count, GET_LOCK_UNLOCK,
391
353
                               &write_lock_used)))
392
354
    mysql_unlock_tables(session, sql_lock);
393
355
}
425
387
  for (i=found=0 ; i < sql_lock->table_count ; i++)
426
388
  {
427
389
    assert(sql_lock->table[i]->lock_position == i);
428
 
    if ((uint32_t) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
 
390
    if ((uint) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
429
391
    {
430
392
      std::swap(*table, sql_lock->table[i]);
431
393
      table++;
473
435
                          effect is desired.
474
436
*/
475
437
 
476
 
void mysql_lock_remove(Session *session, Table *table)
477
 
{
478
 
  mysql_unlock_some_tables(session, &table, /* table count */ 1);
 
438
void mysql_lock_remove(Session *session, DRIZZLE_LOCK *locked,Table *table,
 
439
                       bool always_unlock)
 
440
{
 
441
  if (always_unlock == true)
 
442
    mysql_unlock_some_tables(session, &table, /* table count */ 1);
 
443
  if (locked)
 
444
  {
 
445
    register uint32_t i;
 
446
    for (i=0; i < locked->table_count; i++)
 
447
    {
 
448
      if (locked->table[i] == table)
 
449
      {
 
450
        uint32_t  j, removed_locks, old_tables;
 
451
        Table *tbl;
 
452
        uint32_t lock_data_end;
 
453
 
 
454
        assert(table->lock_position == i);
 
455
 
 
456
        /* Unlock if not yet unlocked */
 
457
        if (always_unlock == false)
 
458
          mysql_unlock_some_tables(session, &table, /* table count */ 1);
 
459
 
 
460
        /* Decrement table_count in advance, making below expressions easier */
 
461
        old_tables= --locked->table_count;
 
462
 
 
463
        /* The table has 'removed_locks' lock data elements in locked->locks */
 
464
        removed_locks= table->lock_count;
 
465
 
 
466
        /* Move down all table pointers above 'i'. */
 
467
        memcpy((locked->table+i), (locked->table+i+1),
 
468
               (old_tables - i) * sizeof(Table*));
 
469
 
 
470
        lock_data_end= table->lock_data_start + table->lock_count;
 
471
        /* Move down all lock data pointers above 'table->lock_data_end-1' */
 
472
        memcpy((locked->locks + table->lock_data_start),
 
473
               (locked->locks + lock_data_end),
 
474
               (locked->lock_count - lock_data_end) *
 
475
               sizeof(THR_LOCK_DATA*));
 
476
 
 
477
        /*
 
478
          Fix moved table elements.
 
479
          lock_position is the index in the 'locked->table' array,
 
480
          it must be fixed by one.
 
481
          table->lock_data_start is pointer to the lock data for this table
 
482
          in the 'locked->locks' array, they must be fixed by 'removed_locks',
 
483
          the lock data count of the removed table.
 
484
        */
 
485
        for (j= i ; j < old_tables; j++)
 
486
        {
 
487
          tbl= locked->table[j];
 
488
          tbl->lock_position--;
 
489
          assert(tbl->lock_position == j);
 
490
          tbl->lock_data_start-= removed_locks;
 
491
        }
 
492
 
 
493
        /* Finally adjust lock_count. */
 
494
        locked->lock_count-= removed_locks;
 
495
        break;
 
496
      }
 
497
    }
 
498
  }
 
499
}
 
500
 
 
501
/* Downgrade all locks on a table to new WRITE level from WRITE_ONLY */
 
502
 
 
503
void mysql_lock_downgrade_write(Session *session, Table *table,
 
504
                                thr_lock_type new_lock_type)
 
505
{
 
506
  DRIZZLE_LOCK *locked;
 
507
  Table *write_lock_used;
 
508
  if ((locked = get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
 
509
                              &write_lock_used)))
 
510
  {
 
511
    for (uint32_t i=0; i < locked->lock_count; i++)
 
512
      thr_downgrade_write_lock(locked->locks[i], new_lock_type);
 
513
    free((unsigned char*) locked);
 
514
  }
479
515
}
480
516
 
481
517
 
482
518
/** Abort all other threads waiting to get lock in table. */
483
519
 
484
 
void mysql_lock_abort(Session *session, Table *table)
 
520
void mysql_lock_abort(Session *session, Table *table, bool upgrade_lock)
485
521
{
486
522
  DRIZZLE_LOCK *locked;
487
523
  Table *write_lock_used;
488
524
 
489
 
  if ((locked= get_lock_data(session, &table, 1, false,
 
525
  if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
490
526
                             &write_lock_used)))
491
527
  {
492
 
    for (uint32_t x= 0; x < locked->lock_count; x++)
493
 
      thr_abort_locks(locked->locks[x]->lock);
 
528
    for (uint32_t i=0; i < locked->lock_count; i++)
 
529
      thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
494
530
    free((unsigned char*) locked);
495
531
  }
 
532
  return;
496
533
}
497
534
 
498
535
 
514
551
  Table *write_lock_used;
515
552
  bool result= false;
516
553
 
517
 
  if ((locked= get_lock_data(session, &table, 1, false,
 
554
  if ((locked= get_lock_data(session, &table, 1, GET_LOCK_UNLOCK,
518
555
                             &write_lock_used)))
519
556
  {
520
557
    for (uint32_t i=0; i < locked->lock_count; i++)
525
562
    }
526
563
    free((unsigned char*) locked);
527
564
  }
528
 
  return result;
529
 
}
 
565
  return(result);
 
566
}
 
567
 
 
568
 
 
569
DRIZZLE_LOCK *mysql_lock_merge(DRIZZLE_LOCK *a,DRIZZLE_LOCK *b)
 
570
{
 
571
  DRIZZLE_LOCK *sql_lock;
 
572
  Table **table, **end_table;
 
573
 
 
574
  if (!(sql_lock= (DRIZZLE_LOCK*)
 
575
        my_malloc(sizeof(*sql_lock)+
 
576
                  sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
 
577
                  sizeof(Table*)*(a->table_count+b->table_count),MYF(MY_WME))))
 
578
    return(0);                          // Fatal error
 
579
  sql_lock->lock_count=a->lock_count+b->lock_count;
 
580
  sql_lock->table_count=a->table_count+b->table_count;
 
581
  sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
 
582
  sql_lock->table=(Table**) (sql_lock->locks+sql_lock->lock_count);
 
583
  memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
 
584
  memcpy(sql_lock->locks+a->lock_count,b->locks,
 
585
         b->lock_count*sizeof(*b->locks));
 
586
  memcpy(sql_lock->table,a->table,a->table_count*sizeof(*a->table));
 
587
  memcpy(sql_lock->table+a->table_count,b->table,
 
588
         b->table_count*sizeof(*b->table));
 
589
 
 
590
  /*
 
591
    Now adjust lock_position and lock_data_start for all objects that was
 
592
    moved in 'b' (as there is now all objects in 'a' before these).
 
593
  */
 
594
  for (table= sql_lock->table + a->table_count,
 
595
         end_table= table + b->table_count;
 
596
       table < end_table;
 
597
       table++)
 
598
  {
 
599
    (*table)->lock_position+=   a->table_count;
 
600
    (*table)->lock_data_start+= a->lock_count;
 
601
  }
 
602
 
 
603
  /* Delete old, not needed locks */
 
604
  free((unsigned char*) a);
 
605
  free((unsigned char*) b);
 
606
  return(sql_lock);
 
607
}
 
608
 
 
609
 
 
610
/**
 
611
  Find duplicate lock in tables.
 
612
 
 
613
  Temporary tables are ignored here like they are ignored in
 
614
  get_lock_data(). If we allow two opens on temporary tables later,
 
615
  both functions should be checked.
 
616
 
 
617
  @param session                 The current thread.
 
618
  @param needle              The table to check for duplicate lock.
 
619
  @param haystack            The list of tables to search for the dup lock.
 
620
 
 
621
  @note
 
622
    This is mainly meant for MERGE tables in INSERT ... SELECT
 
623
    situations. The 'real', underlying tables can be found only after
 
624
    the MERGE tables are opened. This function assumes that the tables are
 
625
    already locked.
 
626
 
 
627
  @retval
 
628
    NULL    No duplicate lock found.
 
629
  @retval
 
630
    !NULL   First table from 'haystack' that matches a lock on 'needle'.
 
631
*/
 
632
 
 
633
TableList *mysql_lock_have_duplicate(Session *session, TableList *needle,
 
634
                                      TableList *haystack)
 
635
{
 
636
  DRIZZLE_LOCK            *mylock;
 
637
  Table                 **lock_tables;
 
638
  Table                 *table;
 
639
  Table                 *table2;
 
640
  THR_LOCK_DATA         **lock_locks;
 
641
  THR_LOCK_DATA         **table_lock_data;
 
642
  THR_LOCK_DATA         **end_data;
 
643
  THR_LOCK_DATA         **lock_data2;
 
644
  THR_LOCK_DATA         **end_data2;
 
645
 
 
646
  /*
 
647
    Table may not be defined for derived or view tables.
 
648
    Table may not be part of a lock for delayed operations.
 
649
  */
 
650
  if (! (table= needle->table) || ! table->lock_count)
 
651
    goto end;
 
652
 
 
653
  /* A temporary table does not have locks. */
 
654
  if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
 
655
    goto end;
 
656
 
 
657
  /* Get command lock or LOCK TABLES lock. Maybe empty for INSERT DELAYED. */
 
658
  if (! (mylock= session->lock ? session->lock : session->locked_tables))
 
659
    goto end;
 
660
 
 
661
  /* If we have less than two tables, we cannot have duplicates. */
 
662
  if (mylock->table_count < 2)
 
663
    goto end;
 
664
 
 
665
  lock_locks=  mylock->locks;
 
666
  lock_tables= mylock->table;
 
667
 
 
668
  /* Prepare table related variables that don't change in loop. */
 
669
  assert((table->lock_position < mylock->table_count) &&
 
670
              (table == lock_tables[table->lock_position]));
 
671
  table_lock_data= lock_locks + table->lock_data_start;
 
672
  end_data= table_lock_data + table->lock_count;
 
673
 
 
674
  for (; haystack; haystack= haystack->next_global)
 
675
  {
 
676
    if (haystack->placeholder())
 
677
      continue;
 
678
    table2= haystack->table;
 
679
    if (table2->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
 
680
      continue;
 
681
 
 
682
    /* All tables in list must be in lock. */
 
683
    assert((table2->lock_position < mylock->table_count) &&
 
684
                (table2 == lock_tables[table2->lock_position]));
 
685
 
 
686
    for (lock_data2=  lock_locks + table2->lock_data_start,
 
687
           end_data2= lock_data2 + table2->lock_count;
 
688
         lock_data2 < end_data2;
 
689
         lock_data2++)
 
690
    {
 
691
      THR_LOCK_DATA **lock_data;
 
692
      THR_LOCK *lock2= (*lock_data2)->lock;
 
693
 
 
694
      for (lock_data= table_lock_data;
 
695
           lock_data < end_data;
 
696
           lock_data++)
 
697
      {
 
698
        if ((*lock_data)->lock == lock2)
 
699
        {
 
700
          return(haystack);
 
701
        }
 
702
      }
 
703
    }
 
704
  }
 
705
 
 
706
 end:
 
707
  return(NULL);
 
708
}
 
709
 
530
710
 
531
711
/** Unlock a set of external. */
532
712
 
540
720
    if ((*table)->current_lock != F_UNLCK)
541
721
    {
542
722
      (*table)->current_lock = F_UNLCK;
543
 
      if ((error=(*table)->cursor->ha_external_lock(session, F_UNLCK)))
 
723
      if ((error=(*table)->file->ha_external_lock(session, F_UNLCK)))
544
724
      {
545
725
        error_code=error;
546
 
        print_lock_error(error_code, (*table)->cursor->engine->getName().c_str());
 
726
        print_lock_error(error_code, (*table)->file->table_type());
547
727
      }
548
728
    }
549
729
    table++;
550
730
  } while (--count);
551
 
  return error_code;
 
731
  return(error_code);
552
732
}
553
733
 
554
734
 
557
737
 
558
738
  @param session                    Thread handler
559
739
  @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
 
740
  @param flags              One of:
 
741
           - GET_LOCK_UNLOCK      : If we should send TL_IGNORE to store lock
 
742
           - GET_LOCK_STORE_LOCKS : Store lock info in Table
563
743
  @param write_lock_used   Store pointer to last table with WRITE_ALLOW_WRITE
564
744
*/
565
745
 
566
746
static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
567
 
                                 bool should_lock, Table **write_lock_used)
 
747
                                 uint32_t flags, Table **write_lock_used)
568
748
{
569
749
  uint32_t i,tables,lock_count;
570
750
  DRIZZLE_LOCK *sql_lock;
571
751
  THR_LOCK_DATA **locks, **locks_buf, **locks_start;
572
752
  Table **to, **table_buf;
573
753
 
 
754
  assert((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
 
755
 
574
756
  *write_lock_used=0;
575
 
  for (i= tables= lock_count= 0 ; i < count ; i++)
 
757
  for (i=tables=lock_count=0 ; i < count ; i++)
576
758
  {
577
759
    Table *t= table_ptr[i];
578
760
 
579
 
    if (! (t->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK)))
 
761
    if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
580
762
    {
581
 
      tables++;
 
763
      tables+= t->file->lock_count();
582
764
      lock_count++;
583
765
    }
584
766
  }
590
772
    from the first part immediately before calling thr_multi_lock().
591
773
  */
592
774
  if (!(sql_lock= (DRIZZLE_LOCK*)
593
 
        malloc(sizeof(*sql_lock) +
594
 
               sizeof(THR_LOCK_DATA*) * tables * 2 +
595
 
               sizeof(table_ptr) * lock_count)))
596
 
    return NULL;
 
775
        my_malloc(sizeof(*sql_lock) +
 
776
                  sizeof(THR_LOCK_DATA*) * tables * 2 +
 
777
                  sizeof(table_ptr) * lock_count,
 
778
                  MYF(0))))
 
779
    return(0);
597
780
  locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
598
781
  to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
599
 
  sql_lock->table_count= lock_count;
 
782
  sql_lock->table_count=lock_count;
600
783
 
601
784
  for (i=0 ; i < count ; i++)
602
785
  {
603
786
    Table *table;
604
787
    enum thr_lock_type lock_type;
605
788
 
606
 
    if (table_ptr[i]->getEngine()->check_flag(HTON_BIT_SKIP_STORE_LOCK))
 
789
    if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
607
790
      continue;
608
 
 
609
 
    table= table_ptr[i];
610
791
    lock_type= table->reginfo.lock_type;
611
792
    assert (lock_type != TL_WRITE_DEFAULT);
612
793
    if (lock_type >= TL_WRITE_ALLOW_WRITE)
618
799
        /* Clear the lock type of the lock data that are stored already. */
619
800
        sql_lock->lock_count= locks - sql_lock->locks;
620
801
        reset_lock_data_and_free(&sql_lock);
621
 
        return NULL;
 
802
        return(0);
622
803
      }
623
804
    }
624
805
    locks_start= locks;
625
 
    locks= table->cursor->store_lock(session, locks,
626
 
                                   should_lock == false ? TL_IGNORE : lock_type);
627
 
    if (should_lock)
 
806
    locks= table->file->store_lock(session, locks,
 
807
                                   (flags & GET_LOCK_UNLOCK) ? TL_IGNORE :
 
808
                                   lock_type);
 
809
    if (flags & GET_LOCK_STORE_LOCKS)
628
810
    {
629
 
      table->lock_position=   (uint32_t) (to - table_buf);
630
 
      table->lock_data_start= (uint32_t) (locks_start - locks_buf);
631
 
      table->lock_count=      (uint32_t) (locks - locks_start);
632
 
      assert(table->lock_count == 1);
 
811
      table->lock_position=   (uint) (to - table_buf);
 
812
      table->lock_data_start= (uint) (locks_start - locks_buf);
 
813
      table->lock_count=      (uint) (locks - locks_start);
633
814
    }
634
815
    *to++= table;
635
816
  }
648
829
    And in the FLUSH case, the memory is released quickly anyway.
649
830
  */
650
831
  sql_lock->lock_count= locks - locks_buf;
651
 
 
652
 
  return sql_lock;
 
832
  return(sql_lock);
 
833
}
 
834
 
 
835
 
 
836
/*****************************************************************************
 
837
  Lock table based on the name.
 
838
  This is used when we need total access to a closed, not open table
 
839
*****************************************************************************/
 
840
 
 
841
/**
 
842
  Lock and wait for the named lock.
 
843
 
 
844
  @param session                        Thread handler
 
845
  @param table_list             Lock first table in this list
 
846
 
 
847
 
 
848
  @note
 
849
    Works together with global read lock.
 
850
 
 
851
  @retval
 
852
    0   ok
 
853
  @retval
 
854
    1   error
 
855
*/
 
856
 
 
857
int lock_and_wait_for_table_name(Session *session, TableList *table_list)
 
858
{
 
859
  int lock_retcode;
 
860
  int error= -1;
 
861
 
 
862
  if (wait_if_global_read_lock(session, 0, 1))
 
863
    return(1);
 
864
  pthread_mutex_lock(&LOCK_open);
 
865
  if ((lock_retcode = lock_table_name(session, table_list, true)) < 0)
 
866
    goto end;
 
867
  if (lock_retcode && wait_for_locked_table_names(session, table_list))
 
868
  {
 
869
    unlock_table_name(session, table_list);
 
870
    goto end;
 
871
  }
 
872
  error=0;
 
873
 
 
874
end:
 
875
  pthread_mutex_unlock(&LOCK_open);
 
876
  start_waiting_global_read_lock(session);
 
877
  return(error);
653
878
}
654
879
 
655
880
 
665
890
 
666
891
  @warning
667
892
    If you are going to update the table, you should use
668
 
    lock_and_wait_for_table_name(removed) instead of this function as this works
 
893
    lock_and_wait_for_table_name instead of this function as this works
669
894
    together with 'FLUSH TABLES WITH READ LOCK'
670
895
 
671
896
  @note
689
914
  bool  found_locked_table= false;
690
915
  HASH_SEARCH_STATE state;
691
916
 
692
 
  key_length= table_list->create_table_def_key(key);
 
917
  key_length= create_table_def_key(session, key, table_list, 0);
693
918
 
694
919
  if (check_in_use)
695
920
  {
711
936
      {
712
937
        table->s->version= 0;                  // Ensure no one can use this
713
938
        table->locked_by_name= 1;
714
 
        return 0;
 
939
        return(0);
715
940
      }
716
941
    }
717
942
  }
718
943
 
719
 
  if (!(table= session->table_cache_insert_placeholder(key, key_length)))
720
 
    return -1;
 
944
  if (session->locked_tables && session->locked_tables->table_count &&
 
945
      ! find_temporary_table(session, table_list->db, table_list->table_name))
 
946
  {
 
947
    if (found_locked_table)
 
948
      my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias);
 
949
    else
 
950
      my_error(ER_TABLE_NOT_LOCKED, MYF(0), table_list->alias);
 
951
 
 
952
    return(-1);
 
953
  }
 
954
 
 
955
  if (!(table= table_cache_insert_placeholder(session, key, key_length)))
 
956
    return(-1);
721
957
 
722
958
  table_list->table=table;
723
959
 
727
963
}
728
964
 
729
965
 
730
 
void unlock_table_name(TableList *table_list)
 
966
void unlock_table_name(Session *session __attribute__((unused)),
 
967
                       TableList *table_list)
731
968
{
732
969
  if (table_list->table)
733
970
  {
737
974
}
738
975
 
739
976
 
740
 
static bool locked_named_table(TableList *table_list)
 
977
static bool locked_named_table(Session *session __attribute__((unused)),
 
978
                               TableList *table_list)
741
979
{
742
980
  for (; table_list ; table_list=table_list->next_local)
743
981
  {
759
997
 
760
998
bool wait_for_locked_table_names(Session *session, TableList *table_list)
761
999
{
762
 
  bool result= false;
 
1000
  bool result=0;
763
1001
 
764
1002
  safe_mutex_assert_owner(&LOCK_open);
765
1003
 
766
 
  while (locked_named_table(table_list))
 
1004
  while (locked_named_table(session,table_list))
767
1005
  {
768
1006
    if (session->killed)
769
1007
    {
770
1008
      result=1;
771
1009
      break;
772
1010
    }
773
 
    session->wait_for_condition(&LOCK_open, &COND_refresh);
774
 
    pthread_mutex_lock(&LOCK_open); /* Wait for a table to unlock and then lock it */
 
1011
    wait_for_condition(session, &LOCK_open, &COND_refresh);
 
1012
    pthread_mutex_lock(&LOCK_open);
775
1013
  }
776
 
  return result;
 
1014
  return(result);
777
1015
}
778
1016
 
779
1017
 
783
1021
  REQUIREMENTS
784
1022
  - One must have a lock on LOCK_open when calling this
785
1023
 
 
1024
  @param session                        Thread handle
786
1025
  @param table_list             Names of tables to lock
787
1026
 
 
1027
  @note
 
1028
    If you are just locking one table, you should use
 
1029
    lock_and_wait_for_table_name().
 
1030
 
788
1031
  @retval
789
1032
    0   ok
790
1033
  @retval
799
1042
  for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
800
1043
  {
801
1044
    int got_lock;
802
 
    if ((got_lock= lock_table_name(session,lock_table, true)) < 0)
 
1045
    if ((got_lock=lock_table_name(session,lock_table, true)) < 0)
803
1046
      goto end;                                 // Fatal error
804
1047
    if (got_lock)
805
1048
      got_all_locks=0;                          // Someone is using table
808
1051
  /* If some table was in use, wait until we got the lock */
809
1052
  if (!got_all_locks && wait_for_locked_table_names(session, table_list))
810
1053
    goto end;
811
 
  return false;
 
1054
  return 0;
812
1055
 
813
1056
end:
814
 
  unlock_table_names(table_list, lock_table);
815
 
 
816
 
  return true;
 
1057
  unlock_table_names(session, table_list, lock_table);
 
1058
  return 1;
817
1059
}
818
1060
 
819
1061
 
823
1065
  @param session        Thread handle.
824
1066
  @param table_list Names of tables to lock.
825
1067
 
826
 
  @note
827
 
    This function needs to be protected by LOCK_open. If we're
 
1068
  @note 
 
1069
    This function needs to be protected by LOCK_open. If we're 
828
1070
    under LOCK TABLES, this function does not work as advertised. Namely,
829
1071
    it does not exclude other threads from using this table and does not
830
1072
    put an exclusive name lock on this table into the table cache.
854
1096
 
855
1097
 
856
1098
/**
 
1099
  Test is 'table' is protected by an exclusive name lock.
 
1100
 
 
1101
  @param[in] session        The current thread handler
 
1102
  @param[in] table_list Table container containing the single table to be
 
1103
                        tested
 
1104
 
 
1105
  @note Needs to be protected by LOCK_open mutex.
 
1106
 
 
1107
  @return Error status code
 
1108
    @retval TRUE Table is protected
 
1109
    @retval FALSE Table is not protected
 
1110
*/
 
1111
 
 
1112
bool
 
1113
is_table_name_exclusively_locked_by_this_thread(Session *session,
 
1114
                                                TableList *table_list)
 
1115
{
 
1116
  char  key[MAX_DBKEY_LENGTH];
 
1117
  uint32_t  key_length;
 
1118
 
 
1119
  key_length= create_table_def_key(session, key, table_list, 0);
 
1120
 
 
1121
  return is_table_name_exclusively_locked_by_this_thread(session, (unsigned char *)key,
 
1122
                                                         key_length);
 
1123
}
 
1124
 
 
1125
 
 
1126
/**
 
1127
  Test is 'table key' is protected by an exclusive name lock.
 
1128
 
 
1129
  @param[in] session        The current thread handler.
 
1130
  @param[in] key
 
1131
  @param[in] key_length
 
1132
 
 
1133
  @note Needs to be protected by LOCK_open mutex
 
1134
 
 
1135
  @retval TRUE Table is protected
 
1136
  @retval FALSE Table is not protected
 
1137
 */
 
1138
 
 
1139
bool
 
1140
is_table_name_exclusively_locked_by_this_thread(Session *session, unsigned char *key,
 
1141
                                                int key_length)
 
1142
{
 
1143
  HASH_SEARCH_STATE state;
 
1144
  Table *table;
 
1145
 
 
1146
  for (table= (Table*) hash_first(&open_cache, key,
 
1147
                                  key_length, &state);
 
1148
       table ;
 
1149
       table= (Table*) hash_next(&open_cache, key,
 
1150
                                 key_length, &state))
 
1151
  {
 
1152
    if (table->in_use == session &&
 
1153
        table->open_placeholder == 1 &&
 
1154
        table->s->version == 0)
 
1155
      return true;
 
1156
  }
 
1157
 
 
1158
  return false;
 
1159
}
 
1160
 
 
1161
/**
857
1162
  Unlock all tables in list with a name lock.
858
1163
 
859
1164
  @param
 
1165
    session                     Thread handle
 
1166
  @param
860
1167
    table_list          Names of tables to unlock
861
1168
  @param
862
1169
    last_table          Don't unlock any tables after this one.
875
1182
    1   Fatal error (end of memory ?)
876
1183
*/
877
1184
 
878
 
void unlock_table_names(TableList *table_list, TableList *last_table)
 
1185
void unlock_table_names(Session *session, TableList *table_list,
 
1186
                        TableList *last_table)
879
1187
{
880
1188
  for (TableList *table= table_list;
881
1189
       table != last_table;
882
1190
       table= table->next_local)
883
 
    unlock_table_name(table);
 
1191
    unlock_table_name(session,table);
884
1192
  broadcast_refresh();
 
1193
  return;
885
1194
}
886
1195
 
887
1196
 
911
1220
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
912
1221
  else
913
1222
    my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
 
1223
 
 
1224
  return;
914
1225
}
915
1226
 
916
1227
 
1013
1324
    if (session->killed)
1014
1325
    {
1015
1326
      session->exit_cond(old_message);
1016
 
      return true;
 
1327
      return(1);
1017
1328
    }
1018
1329
    session->global_read_lock= GOT_GLOBAL_READ_LOCK;
1019
1330
    global_read_lock++;
1027
1338
    forbid it before, or we can have a 3-thread deadlock if 2 do SELECT FOR
1028
1339
    UPDATE and one does FLUSH TABLES WITH READ LOCK).
1029
1340
  */
1030
 
  return false;
 
1341
  return(0);
1031
1342
}
1032
1343
 
1033
1344
 
1046
1357
    pthread_cond_broadcast(&COND_global_read_lock);
1047
1358
  }
1048
1359
  session->global_read_lock= 0;
1049
 
}
1050
 
 
1051
 
static inline bool must_wait(bool is_not_commit)
1052
 
{
1053
 
  return (global_read_lock &&
1054
 
          (is_not_commit ||
1055
 
          global_read_lock_blocks_commit));
1056
 
}
 
1360
 
 
1361
  return;
 
1362
}
 
1363
 
 
1364
#define must_wait (global_read_lock &&                             \
 
1365
                   (is_not_commit ||                               \
 
1366
                    global_read_lock_blocks_commit))
1057
1367
 
1058
1368
bool wait_if_global_read_lock(Session *session, bool abort_on_refresh,
1059
1369
                              bool is_not_commit)
1069
1379
  safe_mutex_assert_not_owner(&LOCK_open);
1070
1380
 
1071
1381
  (void) pthread_mutex_lock(&LOCK_global_read_lock);
1072
 
  if ((need_exit_cond= must_wait(is_not_commit)))
 
1382
  if ((need_exit_cond= must_wait))
1073
1383
  {
1074
1384
    if (session->global_read_lock)              // This thread had the read locks
1075
1385
    {
1082
1392
        This allowance is needed to not break existing versions of innobackup
1083
1393
        which do a BEGIN; INSERT; FLUSH TABLES WITH READ LOCK; COMMIT.
1084
1394
      */
1085
 
      return is_not_commit;
 
1395
      return(is_not_commit);
1086
1396
    }
1087
1397
    old_message=session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1088
1398
                                "Waiting for release of readlock");
1089
 
    while (must_wait(is_not_commit) && ! session->killed &&
 
1399
    while (must_wait && ! session->killed &&
1090
1400
           (!abort_on_refresh || session->version == refresh_version))
1091
1401
    {
1092
1402
      (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
1104
1414
    session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1105
1415
  else
1106
1416
    pthread_mutex_unlock(&LOCK_global_read_lock);
1107
 
  return result;
 
1417
  return(result);
1108
1418
}
1109
1419
 
1110
1420
 
1132
1442
    make_global_read_lock_block_commit(), do nothing.
1133
1443
  */
1134
1444
  if (session->global_read_lock != GOT_GLOBAL_READ_LOCK)
1135
 
    return false;
 
1445
    return(0);
1136
1446
  pthread_mutex_lock(&LOCK_global_read_lock);
1137
1447
  /* increment this BEFORE waiting on cond (otherwise race cond) */
1138
1448
  global_read_lock_blocks_commit++;
 
1449
  /* For testing we set up some blocking, to see if we can be killed */
 
1450
  protect_against_global_read_lock++;
1139
1451
  old_message= session->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock,
1140
1452
                               "Waiting for all running commits to finish");
1141
1453
  while (protect_against_global_read_lock && !session->killed)
1142
1454
    pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock);
 
1455
  protect_against_global_read_lock--;
1143
1456
  if ((error= test(session->killed)))
1144
1457
    global_read_lock_blocks_commit--; // undo what we did
1145
1458
  else
1146
1459
    session->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
1147
1460
  session->exit_cond(old_message); // this unlocks LOCK_global_read_lock
1148
 
  return error;
 
1461
  return(error);
1149
1462
}
1150
1463
 
1151
1464
 
1175
1488
}
1176
1489
 
1177
1490
 
 
1491
/*
 
1492
  Try to get transactional table locks for the tables in the list.
 
1493
 
 
1494
  SYNOPSIS
 
1495
    try_transactional_lock()
 
1496
      session                       Thread handle
 
1497
      table_list                List of tables to lock
 
1498
 
 
1499
  DESCRIPTION
 
1500
    This is called if transactional table locks are requested for all
 
1501
    tables in table_list and no non-transactional locks pre-exist.
 
1502
 
 
1503
  RETURN
 
1504
    0                   OK. All tables are transactional locked.
 
1505
    1                   Error: must fall back to non-transactional locks.
 
1506
    -1                  Error: no recovery possible.
 
1507
*/
 
1508
 
 
1509
int try_transactional_lock(Session *session, TableList *table_list)
 
1510
{
 
1511
  uint32_t          dummy_counter;
 
1512
  int           error;
 
1513
  int           result= 0;
 
1514
 
 
1515
  /* Need to open the tables to be able to access engine methods. */
 
1516
  if (open_tables(session, &table_list, &dummy_counter, 0))
 
1517
  {
 
1518
    /* purecov: begin tested */
 
1519
    return(-1);
 
1520
    /* purecov: end */
 
1521
  }
 
1522
 
 
1523
  /* Required by InnoDB. */
 
1524
  session->in_lock_tables= true;
 
1525
 
 
1526
  if ((error= set_handler_table_locks(session, table_list, true)))
 
1527
  {
 
1528
    /*
 
1529
      Not all transactional locks could be taken. If the error was
 
1530
      something else but "unsupported by storage engine", abort the
 
1531
      execution of this statement.
 
1532
    */
 
1533
    if (error != HA_ERR_WRONG_COMMAND)
 
1534
    {
 
1535
      result= -1;
 
1536
      goto err;
 
1537
    }
 
1538
    /*
 
1539
      Fall back to non-transactional locks because transactional locks
 
1540
      are unsupported by a storage engine. No need to unlock the
 
1541
      successfully taken transactional locks. They go away at end of
 
1542
      transaction anyway.
 
1543
    */
 
1544
    result= 1;
 
1545
  }
 
1546
 
 
1547
 err:
 
1548
  /* We need to explicitly commit if autocommit mode is active. */
 
1549
  (void) ha_autocommit_or_rollback(session, 0);
 
1550
  /* Close the tables. The locks (if taken) persist in the storage engines. */
 
1551
  close_tables_for_reopen(session, &table_list);
 
1552
  session->in_lock_tables= false;
 
1553
  return(result);
 
1554
}
 
1555
 
 
1556
 
 
1557
/*
 
1558
  Check if lock method conversion was done and was allowed.
 
1559
 
 
1560
  SYNOPSIS
 
1561
    check_transactional_lock()
 
1562
      session                       Thread handle
 
1563
      table_list                List of tables to lock
 
1564
 
 
1565
  DESCRIPTION
 
1566
 
 
1567
    Lock method conversion can be done during parsing if one of the
 
1568
    locks is non-transactional. It can also happen if non-transactional
 
1569
    table locks exist when the statement is executed or if a storage
 
1570
    engine does not support transactional table locks.
 
1571
 
 
1572
    Check if transactional table locks have been converted to
 
1573
    non-transactional and if this was allowed. In a running transaction
 
1574
    or in strict mode lock method conversion is not allowed - report an
 
1575
    error. Otherwise it is allowed - issue a warning.
 
1576
 
 
1577
  RETURN
 
1578
    0                   OK. Proceed with non-transactional locks.
 
1579
    -1                  Error: Lock conversion is prohibited.
 
1580
*/
 
1581
 
 
1582
int check_transactional_lock(Session *session, TableList *table_list)
 
1583
{
 
1584
  TableList    *tlist;
 
1585
  int           result= 0;
 
1586
  char          warn_buff[DRIZZLE_ERRMSG_SIZE];
 
1587
 
 
1588
  for (tlist= table_list; tlist; tlist= tlist->next_global)
 
1589
  {
 
1590
 
 
1591
    /*
 
1592
      Unfortunately we cannot use tlist->placeholder() here. This method
 
1593
      returns TRUE if the table is not open, which is always the case
 
1594
      here. Whenever the definition of TableList::placeholder() is
 
1595
      changed, probably this condition needs to be changed too.
 
1596
    */
 
1597
    if (tlist->derived || tlist->schema_table || !tlist->lock_transactional)
 
1598
    {
 
1599
      continue;
 
1600
    }
 
1601
 
 
1602
    /* We must not convert the lock method in strict mode. */
 
1603
    {
 
1604
      my_error(ER_NO_AUTO_CONVERT_LOCK_STRICT, MYF(0),
 
1605
               tlist->alias ? tlist->alias : tlist->table_name);
 
1606
      result= -1;
 
1607
      continue;
 
1608
    }
 
1609
 
 
1610
    /* We must not convert the lock method within an active transaction. */
 
1611
    if (session->active_transaction())
 
1612
    {
 
1613
      my_error(ER_NO_AUTO_CONVERT_LOCK_TRANSACTION, MYF(0),
 
1614
               tlist->alias ? tlist->alias : tlist->table_name);
 
1615
      result= -1;
 
1616
      continue;
 
1617
    }
 
1618
 
 
1619
    /* Warn about the conversion. */
 
1620
    snprintf(warn_buff, sizeof(warn_buff), ER(ER_WARN_AUTO_CONVERT_LOCK),
 
1621
             tlist->alias ? tlist->alias : tlist->table_name);
 
1622
    push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN,
 
1623
                 ER_WARN_AUTO_CONVERT_LOCK, warn_buff);
 
1624
  }
 
1625
 
 
1626
  return(result);
 
1627
}
 
1628
 
 
1629
 
 
1630
/*
 
1631
  Set table locks in the table handler.
 
1632
 
 
1633
  SYNOPSIS
 
1634
    set_handler_table_locks()
 
1635
      session                       Thread handle
 
1636
      table_list                List of tables to lock
 
1637
      transactional             If to lock transactional or non-transactional
 
1638
 
 
1639
  RETURN
 
1640
    0                   OK.
 
1641
    != 0                Error code from handler::lock_table().
 
1642
*/
 
1643
 
 
1644
int set_handler_table_locks(Session *session, TableList *table_list,
 
1645
                            bool transactional)
 
1646
{
 
1647
  TableList    *tlist;
 
1648
  int           error= 0;
 
1649
 
 
1650
  for (tlist= table_list; tlist; tlist= tlist->next_global)
 
1651
  {
 
1652
    int lock_type;
 
1653
    int lock_timeout= -1; /* Use default for non-transactional locks. */
 
1654
 
 
1655
    if (tlist->placeholder())
 
1656
      continue;
 
1657
 
 
1658
    assert((tlist->lock_type == TL_READ) ||
 
1659
                (tlist->lock_type == TL_READ_NO_INSERT) ||
 
1660
                (tlist->lock_type == TL_WRITE_DEFAULT) ||
 
1661
                (tlist->lock_type == TL_WRITE) ||
 
1662
                (tlist->lock_type == TL_WRITE_LOW_PRIORITY));
 
1663
 
 
1664
    /*
 
1665
      Every tlist object has a proper lock_type set. Even if it came in
 
1666
      the list as a base table from a view only.
 
1667
    */
 
1668
    lock_type= ((tlist->lock_type <= TL_READ_NO_INSERT) ?
 
1669
                HA_LOCK_IN_SHARE_MODE : HA_LOCK_IN_EXCLUSIVE_MODE);
 
1670
 
 
1671
    if (transactional)
 
1672
    {
 
1673
      /*
 
1674
        The lock timeout is not set if this table belongs to a view. We
 
1675
        need to take it from the top-level view. After this loop
 
1676
        iteration, lock_timeout is not needed any more. Not even if the
 
1677
        locks are converted to non-transactional locks later.
 
1678
        Non-transactional locks do not support a lock_timeout.
 
1679
      */
 
1680
      lock_timeout= tlist->top_table()->lock_timeout;
 
1681
 
 
1682
      /*
 
1683
        For warning/error reporting we need to set the intended lock
 
1684
        method in the TableList object. It will be used later by
 
1685
        check_transactional_lock(). The lock method is not set if this
 
1686
        table belongs to a view. We can safely set it to transactional
 
1687
        locking here. Even for non-view tables. This function is not
 
1688
        called if non-transactional locking was requested for any
 
1689
        object.
 
1690
      */
 
1691
      tlist->lock_transactional= true;
 
1692
    }
 
1693
 
 
1694
    /*
 
1695
      Because we need to set the lock method (see above) for all
 
1696
      involved tables, we cannot break the loop on an error.
 
1697
      But we do not try more locks after the first error.
 
1698
      However, for non-transactional locking handler::lock_table() is
 
1699
      a hint only. So we continue to call it for other tables.
 
1700
    */
 
1701
    if (!error || !transactional)
 
1702
    {
 
1703
      error= tlist->table->file->lock_table(session, lock_type, lock_timeout);
 
1704
      if (error && transactional && (error != HA_ERR_WRONG_COMMAND))
 
1705
        tlist->table->file->print_error(error, MYF(0));
 
1706
    }
 
1707
  }
 
1708
 
 
1709
  return(error);
 
1710
}
 
1711
 
 
1712
 
1178
1713
/**
1179
1714
  @} (end of group Locking)
1180
1715
*/
1181
 
 
1182
 
} /* namespace drizzled */