sql_base.cc 300 KB
Newer Older
1
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
2

unknown's avatar
unknown committed
3 4
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
6

unknown's avatar
unknown committed
7 8 9 10
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
11

unknown's avatar
unknown committed
12 13 14 15 16
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


17
/* Basic functions needed by many modules */
unknown's avatar
unknown committed
18

19
#include "sql_base.h"                           // setup_table_map
20
#include "my_global.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
21 22
#include "sql_priv.h"
#include "unireg.h"
23
#include "debug_sync.h"
24
#include "lock.h"        // mysql_lock_remove,
25 26 27 28 29
                         // mysql_unlock_tables,
                         // mysql_lock_have_duplicate
#include "sql_show.h"    // append_identifier
#include "strfunc.h"     // find_type
#include "parse_file.h"  // sql_parse_prepare, File_parser
30
#include "sql_view.h"    // mysql_make_view, VIEW_ANY_ACL
31 32 33 34 35 36 37 38 39 40 41 42
#include "sql_parse.h"   // check_table_access
#include "sql_insert.h"  // kill_delayed_threads
#include "sql_acl.h"     // *_ACL, check_grant_all_columns,
                         // check_column_grant_in_table_ref,
                         // get_column_grant
#include "sql_partition.h"               // ALTER_PARTITION_PARAM_TYPE
#include "sql_derived.h" // mysql_derived_prepare,
                         // mysql_handle_derived,
                         // mysql_derived_filling
#include "sql_handler.h" // mysql_ha_flush
#include "sql_partition.h"                      // ALTER_PARTITION_PARAM_TYPE
#include "log_event.h"                          // Query_log_event
43
#include "sql_select.h"
44
#include "sp_head.h"
45
#include "sp.h"
Konstantin Osipov's avatar
Konstantin Osipov committed
46
#include "sp_cache.h"
47
#include "sql_trigger.h"
Konstantin Osipov's avatar
Konstantin Osipov committed
48
#include "transaction.h"
49
#include "sql_prepare.h"
unknown's avatar
unknown committed
50 51 52
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
53
#include "rpl_filter.h"
54
#include "sql_table.h"                          // build_table_filename
55
#include "datadict.h"   // dd_frm_type()
56
#include "sql_hset.h"   // Hash_set
57
#ifdef  __WIN__
unknown's avatar
unknown committed
58 59 60
#include <io.h>
#endif

61

62
bool
63 64 65 66 67 68
No_such_table_error_handler::handle_condition(THD *,
                                              uint sql_errno,
                                              const char*,
                                              MYSQL_ERROR::enum_warning_level,
                                              const char*,
                                              MYSQL_ERROR ** cond_hdl)
Marc Alff's avatar
Marc Alff committed
69 70
{
  *cond_hdl= NULL;
71 72 73
  if (sql_errno == ER_NO_SUCH_TABLE)
  {
    m_handled_errors++;
unknown's avatar
unknown committed
74
    return TRUE;
75 76 77
  }

  m_unhandled_errors++;
unknown's avatar
unknown committed
78
  return FALSE;
79 80 81
}


82
bool No_such_table_error_handler::safely_trapped_errors()
83 84 85 86 87 88 89 90 91
{
  /*
    If m_unhandled_errors != 0, something else, unanticipated, happened,
    so the error is not trapped but returned to the caller.
    Multiple ER_NO_SUCH_TABLE can be raised in case of views.
  */
  return ((m_handled_errors > 0) && (m_unhandled_errors == 0));
}

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154

/**
  This internal handler is used to trap ER_NO_SUCH_TABLE and
  ER_WRONG_MRG_TABLE errors during CHECK/REPAIR TABLE for MERGE
  tables.
*/

class Repair_mrg_table_error_handler : public Internal_error_handler
{
public:
  Repair_mrg_table_error_handler()
    : m_handled_errors(false), m_unhandled_errors(false)
  {}

  bool handle_condition(THD *thd,
                        uint sql_errno,
                        const char* sqlstate,
                        MYSQL_ERROR::enum_warning_level level,
                        const char* msg,
                        MYSQL_ERROR ** cond_hdl);

  /**
    Returns TRUE if there were ER_NO_SUCH_/WRONG_MRG_TABLE and there
    were no unhandled errors. FALSE otherwise.
  */
  bool safely_trapped_errors()
  {
    /*
      Check for m_handled_errors is here for extra safety.
      It can be useful in situation when call to open_table()
      fails because some error which was suppressed by another
      error handler (e.g. in case of MDL deadlock which we
      decided to solve by back-off and retry).
    */
    return (m_handled_errors && (! m_unhandled_errors));
  }

private:
  bool m_handled_errors;
  bool m_unhandled_errors;
};


bool
Repair_mrg_table_error_handler::handle_condition(THD *,
                                                 uint sql_errno,
                                                 const char*,
                                                 MYSQL_ERROR::enum_warning_level level,
                                                 const char*,
                                                 MYSQL_ERROR ** cond_hdl)
{
  *cond_hdl= NULL;
  if (sql_errno == ER_NO_SUCH_TABLE || sql_errno == ER_WRONG_MRG_TABLE)
  {
    m_handled_errors= true;
    return TRUE;
  }

  m_unhandled_errors= true;
  return FALSE;
}


155 156 157 158
/**
  @defgroup Data_Dictionary Data Dictionary
  @{
*/
159

160 161 162 163 164 165 166 167
/**
  Protects table_def_hash, used and unused lists in the
  TABLE_SHARE object, LRU lists of used TABLEs and used
  TABLE_SHAREs, refresh_version and the table id counter.
*/
mysql_mutex_t LOCK_open;

#ifdef HAVE_PSI_INTERFACE
168
static PSI_mutex_key key_LOCK_open;
169
static PSI_mutex_info all_tdc_mutexes[]= {
170
  { &key_LOCK_open, "LOCK_open", PSI_FLAG_GLOBAL }
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
};

/**
  Initialize performance schema instrumentation points
  used by the table cache.
*/

static void init_tdc_psi_keys(void)
{
  const char *category= "sql";
  int count;

  if (PSI_server == NULL)
    return;

  count= array_elements(all_tdc_mutexes);
  PSI_server->register_mutex(category, all_tdc_mutexes, count);
}
#endif /* HAVE_PSI_INTERFACE */


192 193 194 195 196 197 198 199 200 201 202 203 204 205
/**
   Total number of TABLE instances for tables in the table definition cache
   (both in use by threads and not in use). This value is accessible to user
   as "Open_tables" status variable.
*/
uint  table_cache_count= 0;
/**
   List that contains all TABLE instances for tables in the table definition
   cache that are not in use by any thread. Recently used TABLE instances are
   appended to the end of the list. Thus the beginning of the list contains
   tables which have been least recently used.
*/
TABLE *unused_tables;
HASH table_def_cache;
unknown's avatar
unknown committed
206 207
static TABLE_SHARE *oldest_unused_share, end_of_unused_share;
static bool table_def_inited= 0;
Konstantin Osipov's avatar
Konstantin Osipov committed
208
static bool table_def_shutdown_in_progress= 0;
unknown's avatar
unknown committed
209

210 211 212 213
static bool check_and_update_table_version(THD *thd, TABLE_LIST *tables,
                                           TABLE_SHARE *table_share);
static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry);
static bool auto_repair_table(THD *thd, TABLE_LIST *table_list);
unknown's avatar
unknown committed
214
static void free_cache_entry(TABLE *entry);
unknown's avatar
unknown committed
215
static bool
216
has_write_table_with_auto_increment(TABLE_LIST *tables);
unknown's avatar
unknown committed
217

unknown's avatar
unknown committed
218

unknown's avatar
unknown committed
219
uint cached_open_tables(void)
unknown's avatar
unknown committed
220
{
221
  return table_cache_count;
unknown's avatar
unknown committed
222 223
}

unknown's avatar
unknown committed
224

unknown's avatar
unknown committed
225 226 227
#ifdef EXTRA_DEBUG
static void check_unused(void)
{
unknown's avatar
unknown committed
228
  uint count= 0, open_files= 0, idx= 0;
229 230
  TABLE *cur_link, *start_link, *entry;
  TABLE_SHARE *share;
unknown's avatar
unknown committed
231 232 233 234 235 236 237 238 239 240

  if ((start_link=cur_link=unused_tables))
  {
    do
    {
      if (cur_link != cur_link->next->prev || cur_link != cur_link->prev->next)
      {
	DBUG_PRINT("error",("Unused_links aren't linked properly")); /* purecov: inspected */
	return; /* purecov: inspected */
      }
241
    } while (count++ < table_cache_count &&
unknown's avatar
unknown committed
242 243 244 245 246 247
	     (cur_link=cur_link->next) != start_link);
    if (cur_link != start_link)
    {
      DBUG_PRINT("error",("Unused_links aren't connected")); /* purecov: inspected */
    }
  }
248
  for (idx=0 ; idx < table_def_cache.records ; idx++)
unknown's avatar
unknown committed
249
  {
250 251 252 253 254
    share= (TABLE_SHARE*) my_hash_element(&table_def_cache, idx);

    I_P_List_iterator<TABLE, TABLE_share> it(share->free_tables);
    while ((entry= it++))
    {
Konstantin Osipov's avatar
Konstantin Osipov committed
255 256 257 258 259
      /* We must not have TABLEs in the free list that have their file closed. */
      DBUG_ASSERT(entry->db_stat && entry->file);
      /* Merge children should be detached from a merge parent */
      DBUG_ASSERT(! entry->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN));

260 261 262 263
      if (entry->in_use)
      {
        DBUG_PRINT("error",("Used table is in share's list of unused tables")); /* purecov: inspected */
      }
unknown's avatar
unknown committed
264
      count--;
unknown's avatar
unknown committed
265
      open_files++;
266 267 268 269 270 271 272 273 274 275
    }
    it.init(share->used_tables);
    while ((entry= it++))
    {
      if (!entry->in_use)
      {
        DBUG_PRINT("error",("Unused table is in share's list of used tables")); /* purecov: inspected */
      }
      open_files++;
    }
unknown's avatar
unknown committed
276 277 278
  }
  if (count != 0)
  {
279
    DBUG_PRINT("error",("Unused_links doesn't match open_cache: diff: %d", /* purecov: inspected */
unknown's avatar
unknown committed
280 281 282 283 284 285 286
			count)); /* purecov: inspected */
  }
}
#else
#define check_unused()
#endif

unknown's avatar
unknown committed
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312

/*
  Create a table cache key

  SYNOPSIS
    create_table_def_key()
    thd			Thread handler
    key			Create key here (must be of size MAX_DBKEY_LENGTH)
    table_list		Table definition
    tmp_table		Set if table is a tmp table

 IMPLEMENTATION
    The table cache_key is created from:
    db_name + \0
    table_name + \0

    if the table is a tmp table, we add the following to make each tmp table
    unique on the slave:

    4 bytes for master thread id
    4 bytes pseudo thread id

  RETURN
    Length of key
*/

313 314
uint create_table_def_key(THD *thd, char *key,
                          const TABLE_LIST *table_list,
unknown's avatar
unknown committed
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
                          bool tmp_table)
{
  uint key_length= (uint) (strmov(strmov(key, table_list->db)+1,
                                  table_list->table_name)-key)+1;
  if (tmp_table)
  {
    int4store(key + key_length, thd->server_id);
    int4store(key + key_length + 4, thd->variables.pseudo_thread_id);
    key_length+= TMP_TABLE_KEY_EXTRA;
  }
  return key_length;
}



/*****************************************************************************
  Functions to handle table definition cach (TABLE_SHARE)
*****************************************************************************/

334
extern "C" uchar *table_def_key(const uchar *record, size_t *length,
unknown's avatar
unknown committed
335 336 337 338
                               my_bool not_used __attribute__((unused)))
{
  TABLE_SHARE *entry=(TABLE_SHARE*) record;
  *length= entry->table_cache_key.length;
339
  return (uchar*) entry->table_cache_key.str;
unknown's avatar
unknown committed
340 341 342 343 344 345
}


static void table_def_free_entry(TABLE_SHARE *share)
{
  DBUG_ENTER("table_def_free_entry");
346
  mysql_mutex_assert_owner(&LOCK_open);
unknown's avatar
unknown committed
347 348 349 350 351 352 353 354 355 356 357 358 359 360
  if (share->prev)
  {
    /* remove from old_unused_share list */
    *share->prev= share->next;
    share->next->prev= share->prev;
  }
  free_table_share(share);
  DBUG_VOID_RETURN;
}


bool table_def_init(void)
{
  table_def_inited= 1;
361 362 363 364
#ifdef HAVE_PSI_INTERFACE
  init_tdc_psi_keys();
#endif
  mysql_mutex_init(key_LOCK_open, &LOCK_open, MY_MUTEX_INIT_FAST);
unknown's avatar
unknown committed
365 366 367
  oldest_unused_share= &end_of_unused_share;
  end_of_unused_share.prev= &oldest_unused_share;

368

Konstantin Osipov's avatar
Konstantin Osipov committed
369 370 371
  return my_hash_init(&table_def_cache, &my_charset_bin, table_def_size,
                      0, 0, table_def_key,
                      (my_hash_free_key) table_def_free_entry, 0) != 0;
unknown's avatar
unknown committed
372 373 374
}


Konstantin Osipov's avatar
Konstantin Osipov committed
375 376 377 378 379 380 381 382 383 384
/**
  Notify table definition cache that process of shutting down server
  has started so it has to keep number of TABLE and TABLE_SHARE objects
  minimal in order to reduce number of references to pluggable engines.
*/

void table_def_start_shutdown(void)
{
  if (table_def_inited)
  {
385
    mysql_mutex_lock(&LOCK_open);
Konstantin Osipov's avatar
Konstantin Osipov committed
386 387 388 389 390 391 392
    /*
      Ensure that TABLE and TABLE_SHARE objects which are created for
      tables that are open during process of plugins' shutdown are
      immediately released. This keeps number of references to engine
      plugins minimal and allows shutdown to proceed smoothly.
    */
    table_def_shutdown_in_progress= TRUE;
393
    mysql_mutex_unlock(&LOCK_open);
394
    /* Free all cached but unused TABLEs and TABLE_SHAREs. */
395
    close_cached_tables(NULL, NULL, FALSE, LONG_TIMEOUT);
Konstantin Osipov's avatar
Konstantin Osipov committed
396 397 398 399
  }
}


unknown's avatar
unknown committed
400 401 402 403 404 405
void table_def_free(void)
{
  DBUG_ENTER("table_def_free");
  if (table_def_inited)
  {
    table_def_inited= 0;
406
    /* Free table definitions. */
Konstantin Osipov's avatar
Konstantin Osipov committed
407
    my_hash_free(&table_def_cache);
408
    mysql_mutex_destroy(&LOCK_open);
unknown's avatar
unknown committed
409 410 411 412 413 414 415 416 417 418 419
  }
  DBUG_VOID_RETURN;
}


uint cached_table_definitions(void)
{
  return table_def_cache.records;
}


420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
/*
  Auxiliary routines for manipulating with per-share used/unused and
  global unused lists of TABLE objects and table_cache_count counter.
  Responsible for preserving invariants between those lists, counter
  and TABLE::in_use member.
  In fact those routines implement sort of implicit table cache as
  part of table definition cache.
*/


/**
   Add newly created TABLE object for table share which is going
   to be used right away.
*/

static void table_def_add_used_table(THD *thd, TABLE *table)
{
  DBUG_ASSERT(table->in_use == thd);
  table->s->used_tables.push_front(table);
  table_cache_count++;
}


/**
   Prepare used or unused TABLE instance for destruction by removing
   it from share's and global list.
*/

static void table_def_remove_table(TABLE *table)
{
  if (table->in_use)
  {
    /* Remove from per-share chain of used TABLE objects. */
    table->s->used_tables.remove(table);
  }
  else
  {
    /* Remove from per-share chain of unused TABLE objects. */
    table->s->free_tables.remove(table);

    /* And global unused chain. */
    table->next->prev=table->prev;
    table->prev->next=table->next;
    if (table == unused_tables)
    {
      unused_tables=unused_tables->next;
      if (table == unused_tables)
	unused_tables=0;
    }
    check_unused();
  }
  table_cache_count--;
}


/**
   Mark already existing TABLE instance as used.
*/

static void table_def_use_table(THD *thd, TABLE *table)
{
  DBUG_ASSERT(!table->in_use);

  /* Unlink table from list of unused tables for this share. */
  table->s->free_tables.remove(table);
  /* Unlink able from global unused tables list. */
  if (table == unused_tables)
  {						// First unused
    unused_tables=unused_tables->next;	        // Remove from link
    if (table == unused_tables)
      unused_tables=0;
  }
  table->prev->next=table->next;		/* Remove from unused list */
  table->next->prev=table->prev;
  check_unused();
  /* Add table to list of used tables for this share. */
  table->s->used_tables.push_front(table);
  table->in_use= thd;
Konstantin Osipov's avatar
Konstantin Osipov committed
498 499 500 501
  /* The ex-unused table must be fully functional. */
  DBUG_ASSERT(table->db_stat && table->file);
  /* The children must be detached from the table. */
  DBUG_ASSERT(! table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN));
502 503 504 505 506 507 508 509 510 511 512
}


/**
   Mark already existing used TABLE instance as unused.
*/

static void table_def_unuse_table(TABLE *table)
{
  DBUG_ASSERT(table->in_use);

513
  /* We shouldn't put the table to 'unused' list if the share is old. */
514
  DBUG_ASSERT(! table->s->has_old_version());
515

516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
  table->in_use= 0;
  /* Remove table from the list of tables used in this share. */
  table->s->used_tables.remove(table);
  /* Add table to the list of unused TABLE objects for this share. */
  table->s->free_tables.push_front(table);
  /* Also link it last in the global list of unused TABLE objects. */
  if (unused_tables)
  {
    table->next=unused_tables;
    table->prev=unused_tables->prev;
    unused_tables->prev=table;
    table->prev->next=table;
  }
  else
    unused_tables=table->next=table->prev=table;
  check_unused();
}


unknown's avatar
unknown committed
535 536 537 538
/*
  Get TABLE_SHARE for a table.

  get_table_share()
539
  thd			Thread handle
unknown's avatar
unknown committed
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
  table_list		Table that should be opened
  key			Table cache key
  key_length		Length of key
  db_flags		Flags to open_table_def():
			OPEN_VIEW
  error			out: Error code from open_table_def()

  IMPLEMENTATION
    Get a table definition from the table definition cache.
    If it doesn't exist, create a new from the table definition file.

  NOTES
    We must have wrlock on LOCK_open when we come here
    (To be changed later)

  RETURN
   0  Error
   #  Share for table
*/

560
TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
561 562
                             uint key_length, uint db_flags, int *error,
                             my_hash_value_type hash_value)
unknown's avatar
unknown committed
563 564 565 566 567 568
{
  TABLE_SHARE *share;
  DBUG_ENTER("get_table_share");

  *error= 0;

569 570 571 572
  /*
    To be able perform any operation on table we should own
    some kind of metadata lock on it.
  */
573 574 575 576
  DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
                                             table_list->db,
                                             table_list->table_name,
                                             MDL_SHARED));
577

unknown's avatar
unknown committed
578
  /* Read table definition from cache */
579 580
  if ((share= (TABLE_SHARE*) my_hash_search_using_hash_value(&table_def_cache,
                                                             hash_value, (uchar*) key, key_length)))
unknown's avatar
unknown committed
581 582 583 584 585 586 587
    goto found;

  if (!(share= alloc_table_share(table_list, key, key_length)))
  {
    DBUG_RETURN(0);
  }

588
  /*
589
    We assign a new table id under the protection of LOCK_open.
590
    We do this instead of creating a new mutex
591
    and using it for the sole purpose of serializing accesses to a
592
    static variable, we assign the table id here. We assign it to the
593 594 595 596 597 598 599 600 601 602
    share before inserting it into the table_def_cache to be really
    sure that it cannot be read from the cache without having a table
    id assigned.

    CAVEAT. This means that the table cannot be used for
    binlogging/replication purposes, unless get_table_share() has been
    called directly or indirectly.
   */
  assign_new_table_id(share);

603
  if (my_hash_insert(&table_def_cache, (uchar*) share))
unknown's avatar
unknown committed
604 605 606 607 608 609 610
  {
    free_table_share(share);
    DBUG_RETURN(0);				// return error
  }
  if (open_table_def(thd, share, db_flags))
  {
    *error= share->error;
Konstantin Osipov's avatar
Konstantin Osipov committed
611
    (void) my_hash_delete(&table_def_cache, (uchar*) share);
unknown's avatar
unknown committed
612 613 614 615 616 617 618 619
    DBUG_RETURN(0);
  }
  share->ref_count++;				// Mark in use
  DBUG_PRINT("exit", ("share: 0x%lx  ref_count: %u",
                      (ulong) share, share->ref_count));
  DBUG_RETURN(share);

found:
620
  /*
unknown's avatar
unknown committed
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
     We found an existing table definition. Return it if we didn't get
     an error when reading the table definition from file.
  */
  if (share->error)
  {
    /* Table definition contained an error */
    open_table_error(share, share->error, share->open_errno, share->errarg);
    DBUG_RETURN(0);
  }
  if (share->is_view && !(db_flags & OPEN_VIEW))
  {
    open_table_error(share, 1, ENOENT, 0);
    DBUG_RETURN(0);
  }

636 637 638
  ++share->ref_count;

  if (share->ref_count == 1 && share->prev)
unknown's avatar
unknown committed
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
  {
    /*
      Share was not used before and it was in the old_unused_share list
      Unlink share from this list
    */
    DBUG_PRINT("info", ("Unlinking from not used list"));
    *share->prev= share->next;
    share->next->prev= share->prev;
    share->next= 0;
    share->prev= 0;
  }

   /* Free cache if too big */
  while (table_def_cache.records > table_def_size &&
         oldest_unused_share->next)
Konstantin Osipov's avatar
Konstantin Osipov committed
654
    my_hash_delete(&table_def_cache, (uchar*) oldest_unused_share);
unknown's avatar
unknown committed
655 656 657 658 659 660 661

  DBUG_PRINT("exit", ("share: 0x%lx  ref_count: %u",
                      (ulong) share, share->ref_count));
  DBUG_RETURN(share);
}


662
/**
unknown's avatar
unknown committed
663 664
  Get a table share. If it didn't exist, try creating it from engine

665
  For arguments and return values, see get_table_share()
unknown's avatar
unknown committed
666 667
*/

668 669 670 671 672
static TABLE_SHARE *
get_table_share_with_discover(THD *thd, TABLE_LIST *table_list,
                              char *key, uint key_length,
                              uint db_flags, int *error,
                              my_hash_value_type hash_value)
673

unknown's avatar
unknown committed
674 675
{
  TABLE_SHARE *share;
676
  bool exists;
unknown's avatar
unknown committed
677 678
  DBUG_ENTER("get_table_share_with_create");

679 680
  share= get_table_share(thd, table_list, key, key_length, db_flags, error,
                         hash_value);
681 682 683 684 685 686 687 688 689
  /*
    If share is not NULL, we found an existing share.

    If share is NULL, and there is no error, we're inside
    pre-locking, which silences 'ER_NO_SUCH_TABLE' errors
    with the intention to silently drop non-existing tables 
    from the pre-locking list. In this case we still need to try
    auto-discover before returning a NULL share.

690 691 692
    Or, we're inside SHOW CREATE VIEW, which
    also installs a silencer for ER_NO_SUCH_TABLE error.

693
    If share is NULL and the error is ER_NO_SUCH_TABLE, this is
694 695 696 697 698
    the same as above, only that the error was not silenced by
    pre-locking or SHOW CREATE VIEW.

    In both these cases it won't harm to try to discover the
    table.
699 700 701 702 703 704

    Finally, if share is still NULL, it's a real error and we need
    to abort.

    @todo Rework alternative ways to deal with ER_NO_SUCH TABLE.
  */
Marc Alff's avatar
Marc Alff committed
705
  if (share || (thd->is_error() && thd->stmt_da->sql_errno() != ER_NO_SUCH_TABLE))
unknown's avatar
unknown committed
706 707
    DBUG_RETURN(share);

708 709
  *error= 0;

unknown's avatar
unknown committed
710
  /* Table didn't exist. Check if some engine can provide it */
711 712 713 714 715 716 717 718
  if (ha_check_if_table_exists(thd, table_list->db, table_list->table_name,
                               &exists))
  {
    thd->clear_error();
    /* Conventionally, the storage engine API does not report errors. */
    my_error(ER_OUT_OF_RESOURCES, MYF(0));
  }
  else if (! exists)
unknown's avatar
unknown committed
719 720 721
  {
    /*
      No such table in any engine.
722 723
      Hide "Table doesn't exist" errors if the table belongs to a view.
      The check for thd->is_error() is necessary to not push an
724
      unwanted error in case the error was already silenced.
725
      @todo Rework the alternative ways to deal with ER_NO_SUCH TABLE.
unknown's avatar
unknown committed
726
    */
727
    if (thd->is_error())
unknown's avatar
unknown committed
728
    {
729 730 731 732 733 734 735 736 737 738 739 740
      if (table_list->parent_l)
      {
        thd->clear_error();
        my_error(ER_WRONG_MRG_TABLE, MYF(0));
      }
      else if (table_list->belong_to_view)
      {
        TABLE_LIST *view= table_list->belong_to_view;
        thd->clear_error();
        my_error(ER_VIEW_INVALID, MYF(0),
                 view->view_db.str, view->view_name.str);
      }
unknown's avatar
unknown committed
741 742
    }
  }
743
  else
unknown's avatar
unknown committed
744 745
  {
    thd->clear_error();
746
    *error= 7; /* Run auto-discover. */
unknown's avatar
unknown committed
747
  }
748
  DBUG_RETURN(NULL);
unknown's avatar
unknown committed
749 750
}

751

Konstantin Osipov's avatar
Konstantin Osipov committed
752 753
/**
  Mark that we are not using table share anymore.
unknown's avatar
unknown committed
754

Konstantin Osipov's avatar
Konstantin Osipov committed
755
  @param  share   Table share
unknown's avatar
unknown committed
756

Konstantin Osipov's avatar
Konstantin Osipov committed
757 758 759
  If the share has no open tables and (we have done a refresh or
  if we have already too many open table shares) then delete the
  definition.
unknown's avatar
unknown committed
760 761
*/

Konstantin Osipov's avatar
Konstantin Osipov committed
762
void release_table_share(TABLE_SHARE *share)
unknown's avatar
unknown committed
763 764 765 766 767 768 769
{
  DBUG_ENTER("release_table_share");
  DBUG_PRINT("enter",
             ("share: 0x%lx  table: %s.%s  ref_count: %u  version: %lu",
              (ulong) share, share->db.str, share->table_name.str,
              share->ref_count, share->version));

Marc Alff's avatar
Marc Alff committed
770
  mysql_mutex_assert_owner(&LOCK_open);
unknown's avatar
unknown committed
771

772
  DBUG_ASSERT(share->ref_count);
unknown's avatar
unknown committed
773 774
  if (!--share->ref_count)
  {
775
    if (share->has_old_version() || table_def_shutdown_in_progress)
776
      my_hash_delete(&table_def_cache, (uchar*) share);
unknown's avatar
unknown committed
777 778 779 780 781 782 783 784 785 786 787
    else
    {
      /* Link share last in used_table_share list */
      DBUG_PRINT("info",("moving share to unused list"));

      DBUG_ASSERT(share->next == 0);
      share->prev= end_of_unused_share.prev;
      *end_of_unused_share.prev= share;
      end_of_unused_share.prev= &share->next;
      share->next= &end_of_unused_share;

788 789 790 791 792
      if (table_def_cache.records > table_def_size)
      {
        /* Delete the least used share to preserve LRU order. */
        my_hash_delete(&table_def_cache, (uchar*) oldest_unused_share);
      }
unknown's avatar
unknown committed
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814
    }
  }

  DBUG_VOID_RETURN;
}


/*
  Check if table definition exits in cache

  SYNOPSIS
    get_cached_table_share()
    db			Database name
    table_name		Table name

  RETURN
    0  Not cached
    #  TABLE_SHARE for table
*/

TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name)
{
815
  char key[NAME_LEN*2+2];
unknown's avatar
unknown committed
816 817
  TABLE_LIST table_list;
  uint key_length;
Marc Alff's avatar
Marc Alff committed
818
  mysql_mutex_assert_owner(&LOCK_open);
unknown's avatar
unknown committed
819 820 821 822

  table_list.db= (char*) db;
  table_list.table_name= (char*) table_name;
  key_length= create_table_def_key((THD*) 0, key, &table_list, 0);
Konstantin Osipov's avatar
Konstantin Osipov committed
823 824
  return (TABLE_SHARE*) my_hash_search(&table_def_cache,
                                       (uchar*) key, key_length);
unknown's avatar
unknown committed
825 826 827
}  


unknown's avatar
unknown committed
828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845
/*
  Create a list for all open tables matching SQL expression

  SYNOPSIS
    list_open_tables()
    thd			Thread THD
    wild		SQL like expression

  NOTES
    One gets only a list of tables for which one has any kind of privilege.
    db and table names are allocated in result struct, so one doesn't need
    a lock on LOCK_open when traversing the return list.

  RETURN VALUES
    NULL	Error (Probably OOM)
    #		Pointer to list of names of open tables.
*/

846
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild)
847 848
{
  int result = 0;
849
  OPEN_TABLE_LIST **start_list, *open_list;
850 851
  TABLE_LIST table_list;
  DBUG_ENTER("list_open_tables");
852

Marc Alff's avatar
Marc Alff committed
853
  mysql_mutex_lock(&LOCK_open);
854
  bzero((char*) &table_list,sizeof(table_list));
855 856
  start_list= &open_list;
  open_list=0;
857

858
  for (uint idx=0 ; result == 0 && idx < table_def_cache.records; idx++)
859
  {
860
    TABLE_SHARE *share= (TABLE_SHARE *)my_hash_element(&table_def_cache, idx);
861

unknown's avatar
unknown committed
862
    if (db && my_strcasecmp(system_charset_info, db, share->db.str))
863
      continue;
unknown's avatar
unknown committed
864
    if (wild && wild_compare(share->table_name.str, wild, 0))
865
      continue;
866

867
    /* Check if user has SELECT privilege for any column in the table */
unknown's avatar
unknown committed
868 869
    table_list.db=         share->db.str;
    table_list.table_name= share->table_name.str;
870
    table_list.grant.privilege=0;
unknown's avatar
unknown committed
871

872
    if (check_table_access(thd,SELECT_ACL,&table_list, TRUE, 1, TRUE))
873
      continue;
874

875
    if (!(*start_list = (OPEN_TABLE_LIST *)
unknown's avatar
unknown committed
876
	  sql_alloc(sizeof(**start_list)+share->table_cache_key.length)))
877
    {
878
      open_list=0;				// Out of memory
879
      break;
880
    }
881 882
    strmov((*start_list)->table=
	   strmov(((*start_list)->db= (char*) ((*start_list)+1)),
unknown's avatar
unknown committed
883 884
		  share->db.str)+1,
	   share->table_name.str);
885 886 887 888
    (*start_list)->in_use= 0;
    I_P_List_iterator<TABLE, TABLE_share> it(share->used_tables);
    while (it++)
      ++(*start_list)->in_use;
889
    (*start_list)->locked= 0;                   /* Obsolete. */
890
    start_list= &(*start_list)->next;
891
    *start_list=0;
892
  }
Marc Alff's avatar
Marc Alff committed
893
  mysql_mutex_unlock(&LOCK_open);
894
  DBUG_RETURN(open_list);
895
}
unknown's avatar
unknown committed
896 897 898 899 900 901 902 903

/*****************************************************************************
 *	 Functions to free open table cache
 ****************************************************************************/


void intern_close_table(TABLE *table)
{						// Free all structures
unknown's avatar
unknown committed
904
  DBUG_ENTER("intern_close_table");
905 906 907 908
  DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx",
                        table->s ? table->s->db.str : "?",
                        table->s ? table->s->table_name.str : "?",
                        (long) table));
unknown's avatar
unknown committed
909

unknown's avatar
unknown committed
910
  free_io_cache(table);
911
  delete table->triggers;
Konstantin Osipov's avatar
Konstantin Osipov committed
912
  if (table->file)                              // Not true if placeholder
Konstantin Osipov's avatar
Konstantin Osipov committed
913
    (void) closefrm(table, 1);			// close file
unknown's avatar
unknown committed
914
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
915 916
}

917 918 919 920 921 922 923 924 925 926
/*
  Remove table from the open table cache

  SYNOPSIS
    free_cache_entry()
    table		Table to remove

  NOTE
    We need to have a lock on LOCK_open when calling this
*/
unknown's avatar
unknown committed
927 928 929 930 931

static void free_cache_entry(TABLE *table)
{
  DBUG_ENTER("free_cache_entry");

932 933 934
  /* This should be done before releasing table share. */
  table_def_remove_table(table);

unknown's avatar
unknown committed
935
  intern_close_table(table);
936

937
  my_free(table);
unknown's avatar
unknown committed
938 939 940
  DBUG_VOID_RETURN;
}

941
/* Free resources allocated by filesort() and read_record() */
unknown's avatar
unknown committed
942 943 944

void free_io_cache(TABLE *table)
{
945
  DBUG_ENTER("free_io_cache");
unknown's avatar
unknown committed
946
  if (table->sort.io_cache)
unknown's avatar
unknown committed
947
  {
unknown's avatar
unknown committed
948
    close_cached_file(table->sort.io_cache);
949
    my_free(table->sort.io_cache);
unknown's avatar
unknown committed
950
    table->sort.io_cache=0;
unknown's avatar
unknown committed
951
  }
952
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
953 954
}

955

956 957 958 959 960
/**
   Auxiliary function which allows to kill delayed threads for
   particular table identified by its share.

   @param share Table share.
Konstantin Osipov's avatar
Konstantin Osipov committed
961

962
   @pre Caller should have LOCK_open mutex.
963 964 965 966 967 968
*/

static void kill_delayed_threads_for_table(TABLE_SHARE *share)
{
  I_P_List_iterator<TABLE, TABLE_share> it(share->used_tables);
  TABLE *tab;
Konstantin Osipov's avatar
Konstantin Osipov committed
969

970
  mysql_mutex_assert_owner(&LOCK_open);
Konstantin Osipov's avatar
Konstantin Osipov committed
971

972 973 974 975 976 977 978 979
  while ((tab= it++))
  {
    THD *in_use= tab->in_use;

    if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
        ! in_use->killed)
    {
      in_use->killed= THD::KILL_CONNECTION;
980
      mysql_mutex_lock(&in_use->mysys_var->mutex);
981 982
      if (in_use->mysys_var->current_cond)
      {
983 984 985
        mysql_mutex_lock(in_use->mysys_var->current_mutex);
        mysql_cond_broadcast(in_use->mysys_var->current_cond);
        mysql_mutex_unlock(in_use->mysys_var->current_mutex);
986
      }
987
      mysql_mutex_unlock(&in_use->mysys_var->mutex);
988 989 990 991 992
    }
  }
}


993 994 995
/*
  Close all tables which aren't in use by any thread

996 997 998
  @param thd Thread context
  @param tables List of tables to remove from the cache
  @param wait_for_refresh Wait for a impending flush
999
  @param timeout Timeout for waiting for flush to be completed.
1000

1001 1002 1003 1004 1005 1006 1007 1008 1009
  @note THD can be NULL, but then wait_for_refresh must be FALSE
        and tables must be NULL.

  @note When called as part of FLUSH TABLES WITH READ LOCK this function
        ignores metadata locks held by other threads. In order to avoid
        situation when FLUSH TABLES WITH READ LOCK sneaks in at the moment
        when some write-locked table is being reopened (by FLUSH TABLES or
        ALTER TABLE) we have to rely on additional global shared metadata
        lock taken by thread trying to obtain global read lock.
1010
*/
unknown's avatar
unknown committed
1011

1012
bool close_cached_tables(THD *thd, TABLE_LIST *tables,
1013
                         bool wait_for_refresh, ulong timeout)
unknown's avatar
unknown committed
1014
{
1015 1016
  bool result= FALSE;
  bool found= TRUE;
1017
  struct timespec abstime;
unknown's avatar
unknown committed
1018
  DBUG_ENTER("close_cached_tables");
1019
  DBUG_ASSERT(thd || (!wait_for_refresh && !tables));
unknown's avatar
unknown committed
1020

1021
  mysql_mutex_lock(&LOCK_open);
unknown's avatar
unknown committed
1022
  if (!tables)
unknown's avatar
unknown committed
1023
  {
1024 1025 1026
    /*
      Force close of all open tables.

1027
      Note that code in TABLE_SHARE::wait_for_old_version() assumes that
1028 1029 1030 1031 1032 1033
      incrementing of refresh_version and removal of unused tables and
      shares from TDC happens atomically under protection of LOCK_open,
      or putting it another way that TDC does not contain old shares
      which don't have any tables used.
    */
    refresh_version++;
1034 1035
    DBUG_PRINT("tcache", ("incremented global refresh_version to: %lu",
                          refresh_version));
1036
    kill_delayed_threads();
Konstantin Osipov's avatar
Konstantin Osipov committed
1037 1038 1039 1040 1041 1042 1043 1044 1045
    /*
      Get rid of all unused TABLE and TABLE_SHARE instances. By doing
      this we automatically close all tables which were marked as "old".
    */
    while (unused_tables)
      free_cache_entry(unused_tables);
    /* Free table shares which were not freed implicitly by loop above. */
    while (oldest_unused_share->next)
      (void) my_hash_delete(&table_def_cache, (uchar*) oldest_unused_share);
unknown's avatar
unknown committed
1046
  }
unknown's avatar
unknown committed
1047
  else
unknown's avatar
unknown committed
1048
  {
unknown's avatar
unknown committed
1049
    bool found=0;
unknown's avatar
VIEW  
unknown committed
1050
    for (TABLE_LIST *table= tables; table; table= table->next_local)
unknown's avatar
unknown committed
1051
    {
1052 1053 1054 1055 1056
      TABLE_SHARE *share= get_cached_table_share(table->db, table->table_name);

      if (share)
      {
        kill_delayed_threads_for_table(share);
Konstantin Osipov's avatar
Konstantin Osipov committed
1057 1058
        /* tdc_remove_table() also sets TABLE_SHARE::version to 0. */
        tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED, table->db,
1059
                         table->table_name, TRUE);
unknown's avatar
unknown committed
1060
	found=1;
1061
      }
unknown's avatar
unknown committed
1062 1063
    }
    if (!found)
1064
      wait_for_refresh=0;			// Nothing to wait for
unknown's avatar
unknown committed
1065
  }
1066

1067
  mysql_mutex_unlock(&LOCK_open);
1068 1069 1070 1071

  if (!wait_for_refresh)
    DBUG_RETURN(result);

1072
  set_timespec(abstime, timeout);
1073

Konstantin Osipov's avatar
Konstantin Osipov committed
1074
  if (thd->locked_tables_mode)
unknown's avatar
unknown committed
1075 1076
  {
    /*
Konstantin Osipov's avatar
Konstantin Osipov committed
1077
      If we are under LOCK TABLES, we need to reopen the tables without
1078 1079 1080
      opening a door for any concurrent threads to sneak in and get
      lock on our tables. To achieve this we use exclusive metadata
      locks.
unknown's avatar
unknown committed
1081
    */
Konstantin Osipov's avatar
Konstantin Osipov committed
1082 1083 1084
    TABLE_LIST *tables_to_reopen= (tables ? tables :
                                  thd->locked_tables_list.locked_tables());

1085 1086 1087
    /* Close open HANLER instances to avoid self-deadlock. */
    mysql_ha_flush_tables(thd, tables_to_reopen);

Konstantin Osipov's avatar
Konstantin Osipov committed
1088 1089
    for (TABLE_LIST *table_list= tables_to_reopen; table_list;
         table_list= table_list->next_global)
1090
    {
Konstantin Osipov's avatar
Konstantin Osipov committed
1091
      /* A check that the table was locked for write is done by the caller. */
1092
      TABLE *table= find_table_for_mdl_upgrade(thd, table_list->db,
1093
                                               table_list->table_name, TRUE);
Konstantin Osipov's avatar
Konstantin Osipov committed
1094 1095 1096 1097 1098 1099

      /* May return NULL if this table has already been closed via an alias. */
      if (! table)
        continue;

      if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
1100
      {
Konstantin Osipov's avatar
Konstantin Osipov committed
1101 1102
        result= TRUE;
        goto err_with_reopen;
1103
      }
Konstantin Osipov's avatar
Konstantin Osipov committed
1104
      close_all_tables_for_name(thd, table->s, FALSE);
1105 1106 1107 1108 1109
    }
  }

  /* Wait until all threads have closed all the tables we are flushing. */
  DBUG_PRINT("info", ("Waiting for other threads to close their open tables"));
unknown's avatar
unknown committed
1110

1111 1112
  while (found && ! thd->killed)
  {
1113
    TABLE_SHARE *share;
1114 1115
    found= FALSE;
    /*
1116 1117
      To a self-deadlock or deadlocks with other FLUSH threads
      waiting on our open HANDLERs, we have to flush them.
1118
    */
1119
    mysql_ha_flush(thd);
1120
    DEBUG_SYNC(thd, "after_flush_unlock");
1121

1122
    mysql_mutex_lock(&LOCK_open);
1123 1124

    if (!tables)
unknown's avatar
unknown committed
1125
    {
1126
      for (uint idx=0 ; idx < table_def_cache.records ; idx++)
unknown's avatar
unknown committed
1127
      {
1128 1129
        share= (TABLE_SHARE*) my_hash_element(&table_def_cache, idx);
        if (share->has_old_version())
1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
        {
          found= TRUE;
          break;
        }
      }
    }
    else
    {
      for (TABLE_LIST *table= tables; table; table= table->next_local)
      {
1140
        share= get_cached_table_share(table->db, table->table_name);
1141
        if (share && share->has_old_version())
1142 1143 1144 1145
        {
	  found= TRUE;
          break;
        }
unknown's avatar
unknown committed
1146 1147
      }
    }
1148 1149 1150

    if (found)
    {
1151 1152 1153 1154 1155 1156
      /*
        The method below temporarily unlocks LOCK_open and frees
        share's memory.
      */
      if (share->wait_for_old_version(thd, &abstime,
                                    MDL_wait_for_subgraph::DEADLOCK_WEIGHT_DDL))
1157 1158 1159 1160 1161
      {
        mysql_mutex_unlock(&LOCK_open);
        result= TRUE;
        goto err_with_reopen;
      }
1162 1163
    }

1164
    mysql_mutex_unlock(&LOCK_open);
1165 1166 1167
  }

err_with_reopen:
Konstantin Osipov's avatar
Konstantin Osipov committed
1168
  if (thd->locked_tables_mode)
1169
  {
unknown's avatar
unknown committed
1170 1171 1172 1173 1174
    /*
      No other thread has the locked tables open; reopen them and get the
      old locks. This should always succeed (unless some external process
      has removed the tables)
    */
Konstantin Osipov's avatar
Konstantin Osipov committed
1175
    thd->locked_tables_list.reopen_tables(thd);
Konstantin Osipov's avatar
Konstantin Osipov committed
1176
    /*
Konstantin Osipov's avatar
Konstantin Osipov committed
1177 1178
      Since downgrade_exclusive_lock() won't do anything with shared
      metadata lock it is much simpler to go through all open tables rather
Konstantin Osipov's avatar
Konstantin Osipov committed
1179 1180 1181
      than picking only those tables that were flushed.
    */
    for (TABLE *tab= thd->open_tables; tab; tab= tab->next)
1182
      tab->mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
unknown's avatar
unknown committed
1183 1184 1185 1186 1187
  }
  DBUG_RETURN(result);
}


Konstantin Osipov's avatar
Konstantin Osipov committed
1188
/**
1189 1190 1191 1192
  Close all tables which match specified connection string or
  if specified string is NULL, then any table with a connection string.
*/

Konstantin Osipov's avatar
Konstantin Osipov committed
1193
bool close_cached_connection_tables(THD *thd, LEX_STRING *connection)
1194 1195 1196 1197 1198 1199 1200 1201
{
  uint idx;
  TABLE_LIST tmp, *tables= NULL;
  bool result= FALSE;
  DBUG_ENTER("close_cached_connections");
  DBUG_ASSERT(thd);

  bzero(&tmp, sizeof(TABLE_LIST));
1202

1203
  mysql_mutex_lock(&LOCK_open);
1204

1205 1206
  for (idx= 0; idx < table_def_cache.records; idx++)
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
1207
    TABLE_SHARE *share= (TABLE_SHARE *) my_hash_element(&table_def_cache, idx);
1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230

    /* Ignore if table is not open or does not have a connect_string */
    if (!share->connect_string.length || !share->ref_count)
      continue;

    /* Compare the connection string */
    if (connection &&
        (connection->length > share->connect_string.length ||
         (connection->length < share->connect_string.length &&
          (share->connect_string.str[connection->length] != '/' &&
           share->connect_string.str[connection->length] != '\\')) ||
         strncasecmp(connection->str, share->connect_string.str,
                     connection->length)))
      continue;

    /* close_cached_tables() only uses these elements */
    tmp.db= share->db.str;
    tmp.table_name= share->table_name.str;
    tmp.next_local= tables;

    tables= (TABLE_LIST *) memdup_root(thd->mem_root, (char*)&tmp, 
                                       sizeof(TABLE_LIST));
  }
1231
  mysql_mutex_unlock(&LOCK_open);
1232 1233

  if (tables)
1234
    result= close_cached_tables(thd, tables, FALSE, LONG_TIMEOUT);
1235 1236 1237 1238 1239

  DBUG_RETURN(result);
}


1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254
/**
  Mark all temporary tables which were used by the current statement or
  substatement as free for reuse, but only if the query_id can be cleared.

  @param thd thread context

  @remark For temp tables associated with a open SQL HANDLER the query_id
          is not reset until the HANDLER is closed.
*/

static void mark_temp_tables_as_free_for_reuse(THD *thd)
{
  for (TABLE *table= thd->temporary_tables ; table ; table= table->next)
  {
    if ((table->query_id == thd->query_id) && ! table->open_by_handler)
1255 1256 1257
      mark_tmp_table_for_reuse(table);
  }
}
Konstantin Osipov's avatar
Konstantin Osipov committed
1258 1259


1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
/**
  Reset a single temporary table.
  Effectively this "closes" one temporary table,
  in a session.

  @param table     Temporary table.
*/

void mark_tmp_table_for_reuse(TABLE *table)
{
  DBUG_ASSERT(table->s->tmp_table);

  table->query_id= 0;
  table->file->ha_reset();

  /* Detach temporary MERGE children from temporary parent. */
  DBUG_ASSERT(table->file);
  table->file->extra(HA_EXTRA_DETACH_CHILDREN);

  /*
    Reset temporary table lock type to it's default value (TL_WRITE).

    Statements such as INSERT INTO .. SELECT FROM tmp, CREATE TABLE
    .. SELECT FROM tmp and UPDATE may under some circumstances modify
    the lock type of the tables participating in the statement. This
    isn't a problem for non-temporary tables since their lock type is
    reset at every open, but the same does not occur for temporary
    tables for historical reasons.

    Furthermore, the lock type of temporary tables is not really that
    important because they can only be used by one query at a time and
    not even twice in a query -- a temporary table is represented by
    only one TABLE object. Nonetheless, it's safer from a maintenance
    point of view to reset the lock type of this singleton TABLE object
    as to not cause problems when the table is reused.

    Even under LOCK TABLES mode its okay to reset the lock type as
    LOCK TABLES is allowed (but ignored) for a temporary table.
  */
  table->reginfo.lock_type= TL_WRITE;
1300 1301 1302
}


1303
/*
1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314
  Mark all tables in the list which were used by current substatement
  as free for reuse.

  SYNOPSIS
    mark_used_tables_as_free_for_reuse()
      thd   - thread context
      table - head of the list of tables

  DESCRIPTION
    Marks all tables in the list which were used by current substatement
    (they are marked by its query_id) as free for reuse.
1315 1316 1317 1318 1319 1320 1321 1322 1323

  NOTE
    The reason we reset query_id is that it's not enough to just test
    if table->query_id != thd->query_id to know if a table is in use.

    For example
    SELECT f1_that_uses_t1() FROM t1;
    In f1_that_uses_t1() we will see one instance of t1 where query_id is
    set to query_id of original query.
1324 1325 1326 1327 1328
*/

static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
{
  for (; table ; table= table->next)
1329
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
1330 1331
    DBUG_ASSERT(table->pos_in_locked_tables == NULL ||
                table->pos_in_locked_tables->table == table);
1332
    if (table->query_id == thd->query_id)
1333
    {
1334
      table->query_id= 0;
1335 1336 1337
      table->file->ha_reset();
    }
  }
1338 1339 1340
}


1341 1342 1343 1344 1345 1346 1347 1348 1349 1350
/**
  Auxiliary function to close all tables in the open_tables list.

  @param thd Thread context.

  @remark It should not ordinarily be called directly.
*/

static void close_open_tables(THD *thd)
{
Marc Alff's avatar
Marc Alff committed
1351
  mysql_mutex_assert_not_owner(&LOCK_open);
1352 1353 1354 1355

  DBUG_PRINT("info", ("thd->open_tables: 0x%lx", (long) thd->open_tables));

  while (thd->open_tables)
1356
    (void) close_thread_table(thd, &thd->open_tables);
1357 1358 1359
}


Konstantin Osipov's avatar
Konstantin Osipov committed
1360
/**
1361
  Close all open instances of the table but keep the MDL lock.
Konstantin Osipov's avatar
Konstantin Osipov committed
1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374

  Works both under LOCK TABLES and in the normal mode.
  Removes all closed instances of the table from the table cache.

  @param     thd     thread handle
  @param[in] share   table share, but is just a handy way to
                     access the table cache key

  @param[in] remove_from_locked_tables
                     TRUE if the table is being dropped or renamed.
                     In that case the documented behaviour is to
                     implicitly remove the table from LOCK TABLES
                     list.
1375 1376

  @pre Must be called with an X MDL lock on the table.
Konstantin Osipov's avatar
Konstantin Osipov committed
1377 1378 1379 1380 1381 1382 1383 1384
*/

void
close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
                          bool remove_from_locked_tables)
{
  char key[MAX_DBKEY_LENGTH];
  uint key_length= share->table_cache_key.length;
1385 1386
  const char *db= key;
  const char *table_name= db + share->db.length + 1;
Konstantin Osipov's avatar
Konstantin Osipov committed
1387 1388 1389

  memcpy(key, share->table_cache_key.str, key_length);

1390
  mysql_mutex_assert_not_owner(&LOCK_open);
Konstantin Osipov's avatar
Konstantin Osipov committed
1391 1392 1393 1394 1395 1396 1397
  for (TABLE **prev= &thd->open_tables; *prev; )
  {
    TABLE *table= *prev;

    if (table->s->table_cache_key.length == key_length &&
        !memcmp(table->s->table_cache_key.str, key, key_length))
    {
1398 1399 1400
      thd->locked_tables_list.unlink_from_list(thd,
                                               table->pos_in_locked_tables,
                                               remove_from_locked_tables);
Konstantin Osipov's avatar
Konstantin Osipov committed
1401 1402 1403 1404 1405 1406 1407
      /*
        Does nothing if the table is not locked.
        This allows one to use this function after a table
        has been unlocked, e.g. in partition management.
      */
      mysql_lock_remove(thd, thd->lock, table);

1408 1409 1410
      /* Inform handler that table will be dropped after close */
      if (table->db_stat) /* Not true for partitioned tables. */
        table->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
Konstantin Osipov's avatar
Konstantin Osipov committed
1411 1412 1413 1414 1415 1416 1417 1418
      close_thread_table(thd, prev);
    }
    else
    {
      /* Step to next entry in open_tables list. */
      prev= &table->next;
    }
  }
1419
  /* Remove the table share from the cache. */
1420 1421
  tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db, table_name,
                   FALSE);
Konstantin Osipov's avatar
Konstantin Osipov committed
1422 1423 1424
}


1425 1426 1427
/*
  Close all tables used by the current substatement, or all tables
  used by this thread if we are on the upper level.
unknown's avatar
unknown committed
1428

1429 1430 1431 1432 1433 1434 1435
  SYNOPSIS
    close_thread_tables()
    thd			Thread handler

  IMPLEMENTATION
    Unlocks tables and frees derived tables.
    Put all normal tables used by thread in free list.
1436

1437 1438 1439 1440
    It will only close/mark as free for reuse tables opened by this
    substatement, it will also check if we are closing tables after
    execution of complete query (i.e. we are on upper level) and will
    leave prelocked mode if needed.
1441
*/
unknown's avatar
unknown committed
1442

Konstantin Osipov's avatar
Konstantin Osipov committed
1443
void close_thread_tables(THD *thd)
unknown's avatar
unknown committed
1444
{
1445
  TABLE *table;
unknown's avatar
unknown committed
1446 1447
  DBUG_ENTER("close_thread_tables");

1448 1449 1450 1451 1452 1453 1454
#ifdef EXTRA_DEBUG
  DBUG_PRINT("tcache", ("open tables:"));
  for (table= thd->open_tables; table; table= table->next)
    DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", table->s->db.str,
                          table->s->table_name.str, (long) table));
#endif

1455 1456 1457 1458 1459 1460
#if defined(ENABLED_DEBUG_SYNC)
  /* debug_sync may not be initialized for some slave threads */
  if (thd->debug_sync_control)
    DEBUG_SYNC(thd, "before_close_thread_tables");
#endif

1461 1462 1463
  DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt ||
              (thd->state_flags & Open_tables_state::BACKUPS_AVAIL));

Konstantin Osipov's avatar
Konstantin Osipov committed
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477
  /* Detach MERGE children after every statement. Even under LOCK TABLES. */
  for (table= thd->open_tables; table; table= table->next)
  {
    /* Table might be in use by some outer statement. */
    DBUG_PRINT("tcache", ("table: '%s'  query_id: %lu",
                          table->s->table_name.str, (ulong) table->query_id));
    if (thd->locked_tables_mode <= LTM_LOCK_TABLES ||
        table->query_id == thd->query_id)
    {
      DBUG_ASSERT(table->file);
      table->file->extra(HA_EXTRA_DETACH_CHILDREN);
    }
  }

1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488
  /*
    We are assuming here that thd->derived_tables contains ONLY derived
    tables for this substatement. i.e. instead of approach which uses
    query_id matching for determining which of the derived tables belong
    to this substatement we rely on the ability of substatements to
    save/restore thd->derived_tables during their execution.

    TODO: Probably even better approach is to simply associate list of
          derived tables with (sub-)statement instead of thread and destroy
          them at the end of its execution.
  */
1489
  if (thd->derived_tables)
1490
  {
1491
    TABLE *next;
1492
    /*
1493 1494
      Close all derived tables generated in queries like
      SELECT * FROM (SELECT * FROM t1)
1495 1496 1497 1498 1499 1500 1501 1502
    */
    for (table= thd->derived_tables ; table ; table= next)
    {
      next= table->next;
      free_tmp_table(thd, table);
    }
    thd->derived_tables= 0;
  }
1503

1504 1505 1506 1507
  /*
    Mark all temporary tables used by this statement as free for reuse.
  */
  mark_temp_tables_as_free_for_reuse(thd);
1508

Konstantin Osipov's avatar
Konstantin Osipov committed
1509
  if (thd->locked_tables_mode)
1510
  {
1511

1512 1513
    /* Ensure we are calling ha_reset() for all used tables */
    mark_used_tables_as_free_for_reuse(thd, thd->open_tables);
1514

1515 1516 1517
    /*
      We are under simple LOCK TABLES or we're inside a sub-statement
      of a prelocked statement, so should not do anything else.
Konstantin Osipov's avatar
Konstantin Osipov committed
1518 1519 1520 1521 1522

      Note that even if we are in LTM_LOCK_TABLES mode and statement
      requires prelocking (e.g. when we are closing tables after
      failing ot "open" all tables required for statement execution)
      we will exit this function a few lines below.
1523
    */
Konstantin Osipov's avatar
Konstantin Osipov committed
1524
    if (! thd->lex->requires_prelocking())
1525 1526 1527
      DBUG_VOID_RETURN;

    /*
1528 1529 1530
      We are in the top-level statement of a prelocked statement,
      so we have to leave the prelocked mode now with doing implicit
      UNLOCK TABLES if needed.
1531
    */
Konstantin Osipov's avatar
Konstantin Osipov committed
1532 1533
    if (thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
      thd->locked_tables_mode= LTM_LOCK_TABLES;
1534

Konstantin Osipov's avatar
Konstantin Osipov committed
1535
    if (thd->locked_tables_mode == LTM_LOCK_TABLES)
1536 1537
      DBUG_VOID_RETURN;

1538
    thd->leave_locked_tables_mode();
Konstantin Osipov's avatar
Konstantin Osipov committed
1539

1540
    /* Fallthrough */
1541
  }
unknown's avatar
unknown committed
1542 1543 1544

  if (thd->lock)
  {
1545 1546 1547 1548 1549 1550 1551 1552 1553
    /*
      For RBR we flush the pending event just before we unlock all the
      tables.  This means that we are at the end of a topmost
      statement, so we ensure that the STMT_END_F flag is set on the
      pending event.  For statements that are *inside* stored
      functions, the pending event will not be flushed: that will be
      handled either before writing a query log event (inside
      binlog_query()) or when preparing a pending event.
     */
1554
    (void)thd->binlog_flush_pending_rows_event(TRUE);
1555 1556
    mysql_unlock_tables(thd, thd->lock);
    thd->lock=0;
unknown's avatar
unknown committed
1557
  }
1558 1559 1560 1561
  /*
    Closing a MERGE child before the parent would be fatal if the
    other thread tries to abort the MERGE lock in between.
  */
1562 1563
  if (thd->open_tables)
    close_open_tables(thd);
1564

unknown's avatar
unknown committed
1565 1566 1567
  DBUG_VOID_RETURN;
}

1568

1569 1570 1571 1572
/* move one table to free list */

bool close_thread_table(THD *thd, TABLE **table_ptr)
{
1573 1574
  bool found_old_table= 0;
  TABLE *table= *table_ptr;
1575
  DBUG_ENTER("close_thread_table");
1576
  DBUG_ASSERT(table->key_read == 0);
unknown's avatar
unknown committed
1577
  DBUG_ASSERT(!table->file || table->file->inited == handler::NONE);
1578
  mysql_mutex_assert_not_owner(&LOCK_open);
1579 1580 1581 1582 1583 1584 1585 1586
  /*
    The metadata lock must be released after giving back
    the table to the table cache.
  */
  DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
                                             table->s->db.str,
                                             table->s->table_name.str,
                                             MDL_SHARED));
1587
  table->mdl_ticket= NULL;
1588

1589
  mysql_mutex_lock(&thd->LOCK_thd_data);
1590
  *table_ptr=table->next;
1591 1592
  mysql_mutex_unlock(&thd->LOCK_thd_data);

1593 1594 1595 1596 1597 1598 1599 1600 1601
  if (! table->needs_reopen())
  {
    /* Avoid having MERGE tables with attached children in unused_tables. */
    table->file->extra(HA_EXTRA_DETACH_CHILDREN);
    /* Free memory and reset for next loop. */
    free_field_buffers_larger_than(table, MAX_TDC_BLOB_SIZE);
    table->file->ha_reset();
  }

1602
  mysql_mutex_lock(&LOCK_open);
1603

1604
  if (table->s->has_old_version() || table->needs_reopen() ||
Konstantin Osipov's avatar
Konstantin Osipov committed
1605
      table_def_shutdown_in_progress)
1606
  {
1607
    free_cache_entry(table);
1608
    found_old_table= 1;
1609 1610 1611
  }
  else
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
1612
    DBUG_ASSERT(table->file);
1613
    table_def_unuse_table(table);
1614 1615 1616 1617 1618 1619
    /*
      We free the least used table, not the subject table,
      to keep the LRU order.
    */
    if (table_cache_count > table_cache_size)
      free_cache_entry(unused_tables);
1620
  }
1621
  mysql_mutex_unlock(&LOCK_open);
1622 1623 1624
  DBUG_RETURN(found_old_table);
}

unknown's avatar
unknown committed
1625

1626 1627 1628 1629 1630 1631 1632
/* close_temporary_tables' internal, 4 is due to uint4korr definition */
static inline uint  tmpkeyval(THD *thd, TABLE *table)
{
  return uint4korr(table->s->table_cache_key.str + table->s->table_cache_key.length - 4);
}


unknown's avatar
unknown committed
1633 1634
/*
  Close all temporary tables created by 'CREATE TEMPORARY TABLE' for thread
1635
  creates one DROP TEMPORARY TABLE binlog event for each pseudo-thread 
unknown's avatar
unknown committed
1636
*/
unknown's avatar
unknown committed
1637

1638
bool close_temporary_tables(THD *thd)
unknown's avatar
unknown committed
1639
{
1640
  DBUG_ENTER("close_temporary_tables");
1641
  TABLE *table;
Staale Smedseng's avatar
Staale Smedseng committed
1642
  TABLE *next= NULL;
unknown's avatar
unknown committed
1643
  TABLE *prev_table;
1644
  /* Assume thd->variables.option_bits has OPTION_QUOTE_SHOW_CREATE */
unknown's avatar
unknown committed
1645
  bool was_quote_show= TRUE;
1646
  bool error= 0;
unknown's avatar
unknown committed
1647

1648
  if (!thd->temporary_tables)
1649
    DBUG_RETURN(FALSE);
1650

1651
  if (!mysql_bin_log.is_open())
1652
  {
1653 1654
    TABLE *tmp_next;
    for (table= thd->temporary_tables; table; table= tmp_next)
1655
    {
1656
      tmp_next= table->next;
1657 1658 1659
      close_temporary(table, 1, 1);
    }
    thd->temporary_tables= 0;
1660
    DBUG_RETURN(FALSE);
1661 1662
  }

unknown's avatar
unknown committed
1663
  /* Better add "if exists", in case a RESET MASTER has been done */
1664 1665 1666 1667
  const char stub[]= "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ";
  uint stub_len= sizeof(stub) - 1;
  char buf[256];
  String s_query= String(buf, sizeof(buf), system_charset_info);
unknown's avatar
unknown committed
1668
  bool found_user_tables= FALSE;
1669

unknown's avatar
unknown committed
1670 1671
  memcpy(buf, stub, stub_len);

1672
  /*
1673 1674
    Insertion sort of temp tables by pseudo_thread_id to build ordered list
    of sublists of equal pseudo_thread_id
1675
  */
1676 1677

  for (prev_table= thd->temporary_tables, table= prev_table->next;
1678 1679
       table;
       prev_table= table, table= table->next)
unknown's avatar
unknown committed
1680
  {
1681 1682
    TABLE *prev_sorted /* same as for prev_table */, *sorted;
    if (is_user_table(table))
1683
    {
1684 1685 1686 1687
      if (!found_user_tables)
        found_user_tables= true;
      for (prev_sorted= NULL, sorted= thd->temporary_tables; sorted != table;
           prev_sorted= sorted, sorted= sorted->next)
1688
      {
1689 1690
        if (!is_user_table(sorted) ||
            tmpkeyval(thd, sorted) > tmpkeyval(thd, table))
1691
        {
1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704
          /* move into the sorted part of the list from the unsorted */
          prev_table->next= table->next;
          table->next= sorted;
          if (prev_sorted)
          {
            prev_sorted->next= table;
          }
          else
          {
            thd->temporary_tables= table;
          }
          table= prev_table;
          break;
1705 1706 1707
        }
      }
    }
unknown's avatar
unknown committed
1708
  }
1709 1710 1711

  /* We always quote db,table names though it is slight overkill */
  if (found_user_tables &&
1712
      !(was_quote_show= test(thd->variables.option_bits & OPTION_QUOTE_SHOW_CREATE)))
1713
  {
1714
    thd->variables.option_bits |= OPTION_QUOTE_SHOW_CREATE;
unknown's avatar
unknown committed
1715
  }
1716

1717
  /* scan sorted tmps to generate sequence of DROP */
1718
  for (table= thd->temporary_tables; table; table= next)
unknown's avatar
unknown committed
1719
  {
1720
    if (is_user_table(table))
1721
    {
1722
      bool save_thread_specific_used= thd->thread_specific_used;
unknown's avatar
unknown committed
1723
      my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id;
1724 1725
      /* Set pseudo_thread_id to be that of the processed table */
      thd->variables.pseudo_thread_id= tmpkeyval(thd, table);
1726
      String db;
1727
      db.append(table->s->db.str);
1728 1729 1730
      /* Loop forward through all tables that belong to a common database
         within the sublist of common pseudo_thread_id to create single
         DROP query 
unknown's avatar
unknown committed
1731
      */
1732 1733
      for (s_query.length(stub_len);
           table && is_user_table(table) &&
1734
             tmpkeyval(thd, table) == thd->variables.pseudo_thread_id &&
1735 1736
             table->s->db.length == db.length() &&
             strcmp(table->s->db.str, db.ptr()) == 0;
1737 1738
           table= next)
      {
1739
        /*
1740 1741
          We are going to add ` around the table names and possible more
          due to special characters
1742 1743 1744
        */
        append_identifier(thd, &s_query, table->s->table_name.str,
                          strlen(table->s->table_name.str));
1745
        s_query.append(',');
1746 1747 1748 1749
        next= table->next;
        close_temporary(table, 1, 1);
      }
      thd->clear_error();
1750 1751
      CHARSET_INFO *cs_save= thd->variables.character_set_client;
      thd->variables.character_set_client= system_charset_info;
1752
      thd->thread_specific_used= TRUE;
1753 1754
      Query_log_event qinfo(thd, s_query.ptr(),
                            s_query.length() - 1 /* to remove trailing ',' */,
1755
                            FALSE, TRUE, FALSE, 0);
1756
      qinfo.db= db.ptr();
1757
      qinfo.db_len= db.length();
1758
      thd->variables.character_set_client= cs_save;
1759 1760 1761

      thd->stmt_da->can_overwrite_status= TRUE;
      if ((error= (mysql_bin_log.write(&qinfo) || error)))
1762
      {
1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776
        /*
          If we're here following THD::cleanup, thence the connection
          has been closed already. So lets print a message to the
          error log instead of pushing yet another error into the
          stmt_da.

          Also, we keep the error flag so that we propagate the error
          up in the stack. This way, if we're the SQL thread we notice
          that close_temporary_tables failed. (Actually, the SQL
          thread only calls close_temporary_tables while applying old
          Start_log_event_v3 events.)
        */
        sql_print_error("Failed to write the DROP statement for "
                        "temporary tables to binary log");
1777
      }
1778 1779
      thd->stmt_da->can_overwrite_status= FALSE;

unknown's avatar
unknown committed
1780
      thd->variables.pseudo_thread_id= save_pseudo_thread_id;
1781
      thd->thread_specific_used= save_thread_specific_used;
1782
    }
1783
    else
1784 1785 1786
    {
      next= table->next;
      close_temporary(table, 1, 1);
1787
    }
unknown's avatar
unknown committed
1788
  }
1789
  if (!was_quote_show)
1790
    thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */
unknown's avatar
unknown committed
1791
  thd->temporary_tables=0;
1792 1793

  DBUG_RETURN(error);
unknown's avatar
unknown committed
1794 1795
}

1796
/*
1797
  Find table in list.
1798 1799

  SYNOPSIS
1800
    find_table_in_list()
1801
    table		Pointer to table list
1802
    offset		Offset to which list in table structure to use
1803 1804
    db_name		Data base name
    table_name		Table name
unknown's avatar
VIEW  
unknown committed
1805

1806 1807 1808
  NOTES:
    This is called by find_table_in_local_list() and
    find_table_in_global_list().
unknown's avatar
VIEW  
unknown committed
1809 1810 1811 1812 1813 1814

  RETURN VALUES
    NULL	Table not found
    #		Pointer to found table.
*/

1815
TABLE_LIST *find_table_in_list(TABLE_LIST *table,
1816
                               TABLE_LIST *TABLE_LIST::*link,
1817 1818
                               const char *db_name,
                               const char *table_name)
unknown's avatar
VIEW  
unknown committed
1819
{
1820
  for (; table; table= table->*link )
1821
  {
1822 1823 1824 1825
    if ((table->table == 0 || table->table->s->tmp_table == NO_TMP_TABLE) &&
        strcmp(table->db, db_name) == 0 &&
        strcmp(table->table_name, table_name) == 0)
      break;
1826
  }
unknown's avatar
VIEW  
unknown committed
1827 1828 1829 1830
  return table;
}


1831
/**
1832
  Test that table is unique (It's only exists once in the table list)
1833

1834 1835 1836 1837
  @param  thd                   thread handle
  @param  table                 table which should be checked
  @param  table_list            list of tables
  @param  check_alias           whether to check tables' aliases
1838 1839 1840 1841 1842 1843 1844 1845 1846 1847

  NOTE: to exclude derived tables from check we use following mechanism:
    a) during derived table processing set THD::derived_tables_processing
    b) JOIN::prepare set SELECT::exclude_from_table_unique_test if
       THD::derived_tables_processing set. (we can't use JOIN::execute
       because for PS we perform only JOIN::prepare, but we can't set this
       flag in JOIN::prepare if we are not sure that we are in derived table
       processing loop, because multi-update call fix_fields() for some its
       items (which mean JOIN::prepare for subqueries) before unique_table
       call to detect which tables should be locked for write).
1848
    c) find_dup_table skip all tables which belong to SELECT with
1849 1850 1851 1852
       SELECT::exclude_from_table_unique_test set.
    Also SELECT::exclude_from_table_unique_test used to exclude from check
    tables of main SELECT of multi-delete and multi-update

1853 1854 1855 1856
    We also skip tables with TABLE_LIST::prelocking_placeholder set,
    because we want to allow SELECTs from them, and their modification
    will rise the error anyway.

1857 1858
    TODO: when we will have table/view change detection we can do this check
          only once for PS/SP
1859

1860 1861
  @retval !=0  found duplicate
  @retval 0 if table is unique
1862 1863
*/

1864 1865 1866
static
TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
                           bool check_alias)
1867
{
unknown's avatar
unknown committed
1868
  TABLE_LIST *res;
1869
  const char *d_name, *t_name, *t_alias;
1870
  DBUG_ENTER("find_dup_table");
unknown's avatar
unknown committed
1871
  DBUG_PRINT("enter", ("table alias: %s", table->alias));
1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883

  /*
    If this function called for query which update table (INSERT/UPDATE/...)
    then we have in table->table pointer to TABLE object which we are
    updating even if it is VIEW so we need TABLE_LIST of this TABLE object
    to get right names (even if lower_case_table_names used).

    If this function called for CREATE command that we have not opened table
    (table->table equal to 0) and right names is in current TABLE_LIST
    object.
  */
  if (table->table)
1884
  {
1885 1886 1887
    /* All MyISAMMRG children are plain MyISAM tables. */
    DBUG_ASSERT(table->table->file->ht->db_type != DB_TYPE_MRG_MYISAM);

1888 1889 1890 1891 1892 1893 1894 1895 1896
    /* temporary table is always unique */
    if (table->table && table->table->s->tmp_table != NO_TMP_TABLE)
      DBUG_RETURN(0);
    table= table->find_underlying_table(table->table);
    /*
      as far as we have table->table we have to find real TABLE_LIST of
      it in underlying tables
    */
    DBUG_ASSERT(table);
1897
  }
1898 1899
  d_name= table->db;
  t_name= table->table_name;
1900
  t_alias= table->alias;
1901 1902

  DBUG_PRINT("info", ("real table: %s.%s", d_name, t_name));
unknown's avatar
unknown committed
1903
  for (;;)
unknown's avatar
unknown committed
1904
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
1905 1906 1907 1908
    /*
      Table is unique if it is present only once in the global list
      of tables and once in the list of table locks.
    */
1909
    if (! (res= find_table_in_global_list(table_list, d_name, t_name)))
Konstantin Osipov's avatar
Konstantin Osipov committed
1910 1911 1912 1913 1914 1915 1916 1917 1918 1919
      break;

    /* Skip if same underlying table. */
    if (res->table && (res->table == table->table))
      goto next;

    /* Skip if table alias does not match. */
    if (check_alias)
    {
      if (lower_case_table_names ?
unknown's avatar
unknown committed
1920
          my_strcasecmp(files_charset_info, t_alias, res->alias) :
Konstantin Osipov's avatar
Konstantin Osipov committed
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931
          strcmp(t_alias, res->alias))
        goto next;
    }

    /*
      Skip if marked to be excluded (could be a derived table) or if
      entry is a prelocking placeholder.
    */
    if (res->select_lex &&
        !res->select_lex->exclude_from_table_unique_test &&
        !res->prelocking_placeholder)
1932
      break;
Konstantin Osipov's avatar
Konstantin Osipov committed
1933

1934
    /*
1935
      If we found entry of this table or table of SELECT which already
1936
      processed in derived table or top select of multi-update/multi-delete
1937
      (exclude_from_table_unique_test) or prelocking placeholder.
1938
    */
Konstantin Osipov's avatar
Konstantin Osipov committed
1939
next:
1940
    table_list= res->next_global;
1941 1942
    DBUG_PRINT("info",
               ("found same copy of table or table which we should skip"));
unknown's avatar
unknown committed
1943
  }
1944
  DBUG_RETURN(res);
1945 1946 1947
}


1948 1949 1950 1951 1952
/**
  Test that the subject table of INSERT/UPDATE/DELETE/CREATE
  or (in case of MyISAMMRG) one of its children are not used later
  in the query.

1953 1954 1955 1956 1957
  For MyISAMMRG tables, it is assumed that all the underlying
  tables of @c table (if any) are listed right after it and that
  their @c parent_l field points at the main table.


1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983
  @retval non-NULL The table list element for the table that
                   represents the duplicate. 
  @retval NULL     No duplicates found.
*/

TABLE_LIST*
unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
             bool check_alias)
{
  TABLE_LIST *dup;
  if (table->table && table->table->file->ht->db_type == DB_TYPE_MRG_MYISAM)
  {
    TABLE_LIST *child;
    dup= NULL;
    /* Check duplicates of all merge children. */
    for (child= table->next_global; child && child->parent_l == table;
         child= child->next_global)
    {
      if ((dup= find_dup_table(thd, child, child->next_global, check_alias)))
        break;
    }
  }
  else
    dup= find_dup_table(thd, table, table_list, check_alias);
  return dup;
}
1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018
/*
  Issue correct error message in case we found 2 duplicate tables which
  prevent some update operation

  SYNOPSIS
    update_non_unique_table_error()
    update      table which we try to update
    operation   name of update operation
    duplicate   duplicate table which we found

  NOTE:
    here we hide view underlying tables if we have them
*/

void update_non_unique_table_error(TABLE_LIST *update,
                                   const char *operation,
                                   TABLE_LIST *duplicate)
{
  update= update->top_table();
  duplicate= duplicate->top_table();
  if (!update->view || !duplicate->view ||
      update->view == duplicate->view ||
      update->view_name.length != duplicate->view_name.length ||
      update->view_db.length != duplicate->view_db.length ||
      my_strcasecmp(table_alias_charset,
                    update->view_name.str, duplicate->view_name.str) != 0 ||
      my_strcasecmp(table_alias_charset,
                    update->view_db.str, duplicate->view_db.str) != 0)
  {
    /*
      it is not the same view repeated (but it can be parts of the same copy
      of view), so we have to hide underlying tables.
    */
    if (update->view)
    {
2019
      /* Issue the ER_NON_INSERTABLE_TABLE error for an INSERT */
2020
      if (update->view == duplicate->view)
2021 2022 2023
        my_error(!strncmp(operation, "INSERT", 6) ?
                 ER_NON_INSERTABLE_TABLE : ER_NON_UPDATABLE_TABLE, MYF(0),
                 update->alias, operation);
2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040
      else
        my_error(ER_VIEW_PREVENT_UPDATE, MYF(0),
                 (duplicate->view ? duplicate->alias : update->alias),
                 operation, update->alias);
      return;
    }
    if (duplicate->view)
    {
      my_error(ER_VIEW_PREVENT_UPDATE, MYF(0), duplicate->alias, operation,
               update->alias);
      return;
    }
  }
  my_error(ER_UPDATE_TABLE_USED, MYF(0), update->alias);
}


2041 2042 2043 2044 2045 2046 2047
/**
  Find temporary table specified by database and table names in the
  THD::temporary_tables list.

  @return TABLE instance if a temporary table has been found; NULL otherwise.
*/

unknown's avatar
unknown committed
2048
TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name)
unknown's avatar
unknown committed
2049
{
2050
  TABLE_LIST tl;
unknown's avatar
unknown committed
2051

2052 2053 2054 2055
  tl.db= (char*) db;
  tl.table_name= (char*) table_name;

  return find_temporary_table(thd, &tl);
unknown's avatar
unknown committed
2056
}
2057

unknown's avatar
unknown committed
2058

2059 2060 2061 2062 2063 2064 2065 2066
/**
  Find a temporary table specified by TABLE_LIST instance in the
  THD::temporary_tables list.

  @return TABLE instance if a temporary table has been found; NULL otherwise.
*/

TABLE *find_temporary_table(THD *thd, const TABLE_LIST *tl)
unknown's avatar
unknown committed
2067
{
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079
  char key[MAX_DBKEY_LENGTH];
  uint key_length= create_table_def_key(thd, key, tl, 1);

  return find_temporary_table(thd, key, key_length);
}


/**
  Find a temporary table specified by a key in the THD::temporary_tables list.

  @return TABLE instance if a temporary table has been found; NULL otherwise.
*/
unknown's avatar
unknown committed
2080

2081 2082 2083 2084 2085
TABLE *find_temporary_table(THD *thd,
                            const char *table_key,
                            uint table_key_length)
{
  for (TABLE *table= thd->temporary_tables; table; table= table->next)
unknown's avatar
unknown committed
2086
  {
2087 2088
    if (table->s->table_cache_key.length == table_key_length &&
        !memcmp(table->s->table_cache_key.str, table_key, table_key_length))
unknown's avatar
unknown committed
2089
    {
2090
      return table;
unknown's avatar
unknown committed
2091
    }
unknown's avatar
unknown committed
2092
  }
2093 2094

  return NULL;
unknown's avatar
unknown committed
2095 2096
}

unknown's avatar
unknown committed
2097

2098 2099 2100 2101 2102
/**
  Drop a temporary table.

  Try to locate the table in the list of thd->temporary_tables.
  If the table is found:
2103
   - if the table is being used by some outer statement, fail.
Konstantin Osipov's avatar
Konstantin Osipov committed
2104 2105 2106 2107
   - if the table is locked with LOCK TABLES or by prelocking,
   unlock it and remove it from the list of locked tables
   (THD::lock). Currently only transactional temporary tables
   are locked.
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118
   - Close the temporary table, remove its .FRM
   - remove the table from the list of temporary tables

  This function is used to drop user temporary tables, as well as
  internal tables created in CREATE TEMPORARY TABLE ... SELECT
  or ALTER TABLE. Even though part of the work done by this function
  is redundant when the table is internal, as long as we
  link both internal and user temporary tables into the same
  thd->temporary_tables list, it's impossible to tell here whether
  we're dealing with an internal or a user temporary table.

2119 2120 2121 2122
  If is_trans is not null, we return the type of the table:
  either transactional (e.g. innodb) as TRUE or non-transactional
  (e.g. myisam) as FALSE.

2123 2124 2125 2126
  @retval  0  the table was found and dropped successfully.
  @retval  1  the table was not found in the list of temporary tables
              of this thread
  @retval -1  the table is in use by a outer query
unknown's avatar
unknown committed
2127 2128
*/

2129
int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans)
unknown's avatar
unknown committed
2130
{
unknown's avatar
unknown committed
2131
  TABLE *table;
2132
  DBUG_ENTER("drop_temporary_table");
2133 2134
  DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
                          table_list->db, table_list->table_name));
unknown's avatar
unknown committed
2135

unknown's avatar
unknown committed
2136
  if (!(table= find_temporary_table(thd, table_list)))
2137 2138 2139 2140 2141 2142 2143 2144 2145
    DBUG_RETURN(1);

  /* Table might be in use by some outer statement. */
  if (table->query_id && table->query_id != thd->query_id)
  {
    my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
    DBUG_RETURN(-1);
  }

2146 2147 2148
  if (is_trans != NULL)
    *is_trans= table->file->has_transactions();

2149 2150 2151 2152
  /*
    If LOCK TABLES list is not empty and contains this table,
    unlock the table and remove the table from this list.
  */
Konstantin Osipov's avatar
Konstantin Osipov committed
2153
  mysql_lock_remove(thd, thd->lock, table);
unknown's avatar
unknown committed
2154
  close_temporary_table(thd, table, 1, 1);
2155
  DBUG_RETURN(0);
unknown's avatar
unknown committed
2156 2157
}

unknown's avatar
unknown committed
2158
/*
2159
  unlink from thd->temporary tables and close temporary table
unknown's avatar
unknown committed
2160 2161 2162 2163 2164
*/

void close_temporary_table(THD *thd, TABLE *table,
                           bool free_share, bool delete_table)
{
2165 2166 2167 2168 2169
  DBUG_ENTER("close_temporary_table");
  DBUG_PRINT("tmptable", ("closing table: '%s'.'%s' 0x%lx  alias: '%s'",
                          table->s->db.str, table->s->table_name.str,
                          (long) table, table->alias));

2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188
  if (table->prev)
  {
    table->prev->next= table->next;
    if (table->prev->next)
      table->next->prev= table->prev;
  }
  else
  {
    /* removing the item from the list */
    DBUG_ASSERT(table == thd->temporary_tables);
    /*
      slave must reset its temporary list pointer to zero to exclude
      passing non-zero value to end_slave via rli->save_temporary_tables
      when no temp tables opened, see an invariant below.
    */
    thd->temporary_tables= table->next;
    if (thd->temporary_tables)
      table->next->prev= 0;
  }
unknown's avatar
unknown committed
2189
  if (thd->slave_thread)
2190 2191 2192
  {
    /* natural invariant of temporary_tables */
    DBUG_ASSERT(slave_open_temp_tables || !thd->temporary_tables);
unknown's avatar
unknown committed
2193
    slave_open_temp_tables--;
2194
  }
unknown's avatar
unknown committed
2195
  close_temporary(table, free_share, delete_table);
2196
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209
}


/*
  Close and delete a temporary table

  NOTE
    This dosn't unlink table from thd->temporary
    If this is needed, use close_temporary_table()
*/

void close_temporary(TABLE *table, bool free_share, bool delete_table)
{
unknown's avatar
unknown committed
2210
  handlerton *table_type= table->s->db_type();
unknown's avatar
unknown committed
2211
  DBUG_ENTER("close_temporary");
2212 2213
  DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
                          table->s->db.str, table->s->table_name.str));
unknown's avatar
unknown committed
2214 2215 2216 2217 2218 2219 2220 2221

  free_io_cache(table);
  closefrm(table, 0);
  if (delete_table)
    rm_temporary_table(table_type, table->s->path.str);
  if (free_share)
  {
    free_table_share(table->s);
2222
    my_free(table);
unknown's avatar
unknown committed
2223 2224 2225 2226 2227
  }
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
2228 2229 2230 2231 2232 2233 2234
/*
  Used by ALTER TABLE when the table is a temporary one. It changes something
  only if the ALTER contained a RENAME clause (otherwise, table_name is the old
  name).
  Prepares a table cache key, which is the concatenation of db, table_name and
  thd->slave_proxy_id, separated by '\0'.
*/
2235

2236
bool rename_temporary_table(THD* thd, TABLE *table, const char *db,
unknown's avatar
unknown committed
2237 2238 2239
			    const char *table_name)
{
  char *key;
2240
  uint key_length;
2241
  TABLE_SHARE *share= table->s;
unknown's avatar
unknown committed
2242 2243 2244
  TABLE_LIST table_list;
  DBUG_ENTER("rename_temporary_table");

2245
  if (!(key=(char*) alloc_root(&share->mem_root, MAX_DBKEY_LENGTH)))
unknown's avatar
unknown committed
2246 2247 2248 2249
    DBUG_RETURN(1);				/* purecov: inspected */

  table_list.db= (char*) db;
  table_list.table_name= (char*) table_name;
2250 2251
  key_length= create_table_def_key(thd, key, &table_list, 1);
  share->set_table_cache_key(key, key_length);
unknown's avatar
unknown committed
2252
  DBUG_RETURN(0);
unknown's avatar
unknown committed
2253 2254 2255
}


Konstantin Osipov's avatar
Konstantin Osipov committed
2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280
/**
   Force all other threads to stop using the table by upgrading
   metadata lock on it and remove unused TABLE instances from cache.

   @param thd      Thread handler
   @param table    Table to remove from cache
   @param function HA_EXTRA_PREPARE_FOR_DROP if table is to be deleted
                   HA_EXTRA_FORCE_REOPEN if table is not be used
                   HA_EXTRA_PREPARE_FOR_RENAME if table is to be renamed

   @note When returning, the table will be unusable for other threads
         until metadata lock is downgraded.

   @retval FALSE Success.
   @retval TRUE  Failure (e.g. because thread was killed).
*/

bool wait_while_table_is_used(THD *thd, TABLE *table,
                              enum ha_extra_function function)
{
  DBUG_ENTER("wait_while_table_is_used");
  DBUG_PRINT("enter", ("table: '%s'  share: 0x%lx  db_stat: %u  version: %lu",
                       table->s->table_name.str, (ulong) table->s,
                       table->db_stat, table->s->version));

2281 2282
  if (thd->mdl_context.upgrade_shared_lock_to_exclusive(
             table->mdl_ticket, thd->variables.lock_wait_timeout))
Konstantin Osipov's avatar
Konstantin Osipov committed
2283 2284
    DBUG_RETURN(TRUE);

Konstantin Osipov's avatar
Konstantin Osipov committed
2285
  tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN,
2286 2287
                   table->s->db.str, table->s->table_name.str,
                   FALSE);
Konstantin Osipov's avatar
Konstantin Osipov committed
2288 2289
  /* extra() call must come only after all instances above are closed */
  (void) table->file->extra(function);
Konstantin Osipov's avatar
Konstantin Osipov committed
2290 2291 2292 2293 2294
  DBUG_RETURN(FALSE);
}


/**
Konstantin Osipov's avatar
Konstantin Osipov committed
2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310
  Close a and drop a just created table in CREATE TABLE ... SELECT.

  @param  thd         Thread handle
  @param  table       TABLE object for the table to be dropped
  @param  db_name     Name of database for this table
  @param  table_name  Name of this table

  This routine assumes that the table to be closed is open only
  by the calling thread, so we needn't wait until other threads
  close the table. It also assumes that the table is first
  in thd->open_ables and a data lock on it, if any, has been
  released. To sum up, it's tuned to work with
  CREATE TABLE ... SELECT and CREATE TABLE .. SELECT only.
  Note, that currently CREATE TABLE ... SELECT is not supported
  under LOCK TABLES. This function, still, can be called in
  prelocked mode, e.g. if we do CREATE TABLE .. SELECT f1();
unknown's avatar
unknown committed
2311 2312 2313 2314 2315
*/

void drop_open_table(THD *thd, TABLE *table, const char *db_name,
                     const char *table_name)
{
Konstantin Osipov's avatar
Konstantin Osipov committed
2316
  DBUG_ENTER("drop_open_table");
unknown's avatar
unknown committed
2317 2318 2319 2320
  if (table->s->tmp_table)
    close_temporary_table(thd, table, 1, 1);
  else
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
2321 2322
    DBUG_ASSERT(table == thd->open_tables);

unknown's avatar
unknown committed
2323
    handlerton *table_type= table->s->db_type();
Konstantin Osipov's avatar
Konstantin Osipov committed
2324

Konstantin Osipov's avatar
Konstantin Osipov committed
2325
    table->file->extra(HA_EXTRA_PREPARE_FOR_DROP);
Konstantin Osipov's avatar
Konstantin Osipov committed
2326
    close_thread_table(thd, &thd->open_tables);
2327
    /* Remove the table share from the table cache. */
2328 2329
    tdc_remove_table(thd, TDC_RT_REMOVE_ALL, db_name, table_name,
                     FALSE);
2330
    /* Remove the table from the storage engine and rm the .frm. */
unknown's avatar
unknown committed
2331 2332
    quick_rm_table(table_type, db_name, table_name, 0);
  }
Konstantin Osipov's avatar
Konstantin Osipov committed
2333
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2334 2335 2336
}


unknown's avatar
unknown committed
2337
/**
unknown's avatar
unknown committed
2338 2339
    Check that table exists in table definition cache, on disk
    or in some storage engine.
unknown's avatar
unknown committed
2340

unknown's avatar
unknown committed
2341 2342 2343
    @param       thd     Thread context
    @param       table   Table list element
    @param[out]  exists  Out parameter which is set to TRUE if table
unknown's avatar
unknown committed
2344 2345
                         exists and to FALSE otherwise.

2346
    @note This function acquires LOCK_open internally.
unknown's avatar
unknown committed
2347 2348 2349 2350 2351

    @note If there is no .FRM file for the table but it exists in one
          of engines (e.g. it was created on another node of NDB cluster)
          this function will fetch and create proper .FRM file for it.

2352
    @retval  TRUE   Some error occurred
unknown's avatar
unknown committed
2353 2354 2355 2356 2357
    @retval  FALSE  No error. 'exists' out parameter set accordingly.
*/

bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists)
{
2358
  char path[FN_REFLEN + 1];
2359
  TABLE_SHARE *share;
unknown's avatar
unknown committed
2360 2361 2362 2363
  DBUG_ENTER("check_if_table_exists");

  *exists= TRUE;

2364 2365 2366 2367
  DBUG_ASSERT(thd->mdl_context.
              is_lock_owner(MDL_key::TABLE, table->db,
                            table->table_name, MDL_SHARED));

2368
  mysql_mutex_lock(&LOCK_open);
2369 2370
  share= get_cached_table_share(table->db, table->table_name);
  mysql_mutex_unlock(&LOCK_open);
2371

2372
  if (share)
2373
    goto end;
unknown's avatar
unknown committed
2374 2375 2376 2377 2378

  build_table_filename(path, sizeof(path) - 1, table->db, table->table_name,
                       reg_ext, 0);

  if (!access(path, F_OK))
2379
    goto end;
unknown's avatar
unknown committed
2380 2381

  /* .FRM file doesn't exist. Check if some engine can provide it. */
2382
  if (ha_check_if_table_exists(thd, table->db, table->table_name, exists))
unknown's avatar
unknown committed
2383
  {
2384
    my_printf_error(ER_OUT_OF_RESOURCES, "Failed to open '%-.64s', error while "
unknown's avatar
unknown committed
2385
                    "unpacking from engine", MYF(0), table->table_name);
2386
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
2387
  }
2388
end:
2389
  DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
2390 2391 2392
}


2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438
/**
  An error handler which converts, if possible, ER_LOCK_DEADLOCK error
  that can occur when we are trying to acquire a metadata lock to
  a request for back-off and re-start of open_tables() process.
*/

class MDL_deadlock_handler : public Internal_error_handler
{
public:
  MDL_deadlock_handler(Open_table_context *ot_ctx_arg)
    : m_ot_ctx(ot_ctx_arg), m_is_active(FALSE)
  {}

  virtual ~MDL_deadlock_handler() {}

  virtual bool handle_condition(THD *thd,
                                uint sql_errno,
                                const char* sqlstate,
                                MYSQL_ERROR::enum_warning_level level,
                                const char* msg,
                                MYSQL_ERROR ** cond_hdl);

private:
  /** Open table context to be used for back-off request. */
  Open_table_context *m_ot_ctx;
  /**
    Indicates that we are already in the process of handling
    ER_LOCK_DEADLOCK error. Allows to re-emit the error from
    the error handler without falling into infinite recursion.
  */
  bool m_is_active;
};


bool MDL_deadlock_handler::handle_condition(THD *,
                                            uint sql_errno,
                                            const char*,
                                            MYSQL_ERROR::enum_warning_level,
                                            const char*,
                                            MYSQL_ERROR ** cond_hdl)
{
  *cond_hdl= NULL;
  if (! m_is_active && sql_errno == ER_LOCK_DEADLOCK)
  {
    /* Disable the handler to avoid infinite recursion. */
    m_is_active= TRUE;
2439 2440 2441
    (void) m_ot_ctx->request_backoff_action(
             Open_table_context::OT_BACKOFF_AND_RETRY,
             NULL);
2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453
    m_is_active= FALSE;
    /*
      If the above back-off request failed, a new instance of
      ER_LOCK_DEADLOCK error was emitted. Thus the current
      instance of error condition can be treated as handled.
    */
    return TRUE;
  }
  return FALSE;
}


Konstantin Osipov's avatar
Konstantin Osipov committed
2454
/**
2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478
  Try to acquire an MDL lock for a table being opened.

  @param[in,out] thd      Session context, to report errors.
  @param[out]    ot_ctx   Open table context, to hold the back off
                          state. If we failed to acquire a lock
                          due to a lock conflict, we add the
                          failed request to the open table context.
  @param[in,out] mdl_request A request for an MDL lock.
                          If we managed to acquire a ticket
                          (no errors or lock conflicts occurred),
                          contains a reference to it on
                          return. However, is not modified if MDL
                          lock type- modifying flags were provided.
  @param[in]    flags flags MYSQL_OPEN_FORCE_SHARED_MDL,
                          MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL or
                          MYSQL_OPEN_FAIL_ON_MDL_CONFLICT
                          @sa open_table().
  @param[out]   mdl_ticket Only modified if there was no error.
                          If we managed to acquire an MDL
                          lock, contains a reference to the
                          ticket, otherwise is set to NULL.

  @retval TRUE  An error occurred.
  @retval FALSE No error, but perhaps a lock conflict, check mdl_ticket.
Konstantin Osipov's avatar
Konstantin Osipov committed
2479 2480 2481
*/

static bool
2482
open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx,
Konstantin Osipov's avatar
Konstantin Osipov committed
2483
                        MDL_request *mdl_request,
2484 2485
                        uint flags,
                        MDL_ticket **mdl_ticket)
Konstantin Osipov's avatar
Konstantin Osipov committed
2486
{
2487 2488
  MDL_request mdl_request_shared;

2489 2490
  if (flags & (MYSQL_OPEN_FORCE_SHARED_MDL |
               MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
Konstantin Osipov's avatar
Konstantin Osipov committed
2491 2492
  {
    /*
2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509
      MYSQL_OPEN_FORCE_SHARED_MDL flag means that we are executing
      PREPARE for a prepared statement and want to override
      the type-of-operation aware metadata lock which was set
      in the parser/during view opening with a simple shared
      metadata lock.
      This is necessary to allow concurrent execution of PREPARE
      and LOCK TABLES WRITE statement against the same table.

      MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL flag means that we open
      the table in order to get information about it for one of I_S
      queries and also want to override the type-of-operation aware
      shared metadata lock which was set earlier (e.g. during view
      opening) with a high-priority shared metadata lock.
      This is necessary to avoid unnecessary waiting and extra
      ER_WARN_I_S_SKIPPED_TABLE warnings when accessing I_S tables.

      These two flags are mutually exclusive.
Konstantin Osipov's avatar
Konstantin Osipov committed
2510
    */
2511 2512
    DBUG_ASSERT(!(flags & MYSQL_OPEN_FORCE_SHARED_MDL) ||
                !(flags & MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL));
2513

2514 2515
    mdl_request_shared.init(&mdl_request->key,
                            (flags & MYSQL_OPEN_FORCE_SHARED_MDL) ?
2516 2517
                            MDL_SHARED : MDL_SHARED_HIGH_PRIO,
                            MDL_TRANSACTION);
2518
    mdl_request= &mdl_request_shared;
Konstantin Osipov's avatar
Konstantin Osipov committed
2519
  }
2520

2521
  if (flags & MYSQL_OPEN_FAIL_ON_MDL_CONFLICT)
2522
  {
2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536
    /*
      When table is being open in order to get data for I_S table,
      we might have some tables not only open but also locked (e.g. when
      this happens under LOCK TABLES or in a stored function).
      As a result by waiting on a conflicting metadata lock to go away
      we may create a deadlock which won't entirely belong to the
      MDL subsystem and thus won't be detectable by this subsystem's
      deadlock detector.
      To avoid such situation we skip the trouble-making table if
      there is a conflicting lock.
    */
    if (thd->mdl_context.try_acquire_lock(mdl_request))
      return TRUE;
    if (mdl_request->ticket == NULL)
Konstantin Osipov's avatar
Konstantin Osipov committed
2537
    {
2538 2539 2540
      my_error(ER_WARN_I_S_SKIPPED_TABLE, MYF(0),
               mdl_request->key.db_name(), mdl_request->key.name());
      return TRUE;
Konstantin Osipov's avatar
Konstantin Osipov committed
2541
    }
2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575
  }
  else
  {
    /*
      We are doing a normal table open. Let us try to acquire a metadata
      lock on the table. If there is a conflicting lock, acquire_lock()
      will wait for it to go away. Sometimes this waiting may lead to a
      deadlock, with the following results:
      1) If a deadlock is entirely within MDL subsystem, it is
         detected by the deadlock detector of this subsystem.
         ER_LOCK_DEADLOCK error is produced. Then, the error handler
         that is installed prior to the call to acquire_lock() attempts
         to request a back-off and retry. Upon success, ER_LOCK_DEADLOCK
         error is suppressed, otherwise propagated up the calling stack.
      2) Otherwise, a deadlock may occur when the wait-for graph
         includes edges not visible to the MDL deadlock detector.
         One such example is a wait on an InnoDB row lock, e.g. when:
         conn C1 gets SR MDL lock on t1 with SELECT * FROM t1
         conn C2 gets a row lock on t2 with  SELECT * FROM t2 FOR UPDATE
         conn C3 gets in and waits on C1 with DROP TABLE t0, t1
         conn C2 continues and blocks on C3 with SELECT * FROM t0
         conn C1 deadlocks by waiting on C2 by issuing SELECT * FROM
         t2 LOCK IN SHARE MODE.
         Such circular waits are currently only resolved by timeouts,
         e.g. @@innodb_lock_wait_timeout or @@lock_wait_timeout.
    */
    MDL_deadlock_handler mdl_deadlock_handler(ot_ctx);

    thd->push_internal_handler(&mdl_deadlock_handler);
    bool result= thd->mdl_context.acquire_lock(mdl_request,
                                               ot_ctx->get_timeout());
    thd->pop_internal_handler();

    if (result && !ot_ctx->can_recover_from_failed_open())
2576
      return TRUE;
Konstantin Osipov's avatar
Konstantin Osipov committed
2577
  }
2578 2579
  *mdl_ticket= mdl_request->ticket;
  return FALSE;
Konstantin Osipov's avatar
Konstantin Osipov committed
2580 2581 2582
}


2583
/**
2584 2585
  Check if table's share is being removed from the table definition
  cache and, if yes, wait until the flush is complete.
2586 2587 2588 2589 2590 2591

  @param thd             Thread context.
  @param table_list      Table which share should be checked.
  @param timeout         Timeout for waiting.
  @param deadlock_weight Weight of this wait for deadlock detector.

2592 2593 2594
  @retval FALSE   Success. Share is up to date or has been flushed.
  @retval TRUE    Error (OOM, our was killed, the wait resulted
                  in a deadlock or timeout). Reported.
2595 2596
*/

2597 2598 2599
static bool
tdc_wait_for_old_version(THD *thd, const char *db, const char *table_name,
                         ulong wait_timeout, uint deadlock_weight)
2600 2601
{
  TABLE_SHARE *share;
2602
  bool res= FALSE;
2603

2604 2605 2606
  mysql_mutex_lock(&LOCK_open);
  if ((share= get_cached_table_share(db, table_name)) &&
      share->has_old_version())
2607 2608
  {
    struct timespec abstime;
2609 2610
    set_timespec(abstime, wait_timeout);
    res= share->wait_for_old_version(thd, &abstime, deadlock_weight);
2611
  }
2612 2613
  mysql_mutex_unlock(&LOCK_open);
  return res;
2614 2615 2616
}


2617 2618 2619 2620 2621
/*
  Open a table.

  SYNOPSIS
    open_table()
2622 2623
    thd                 Thread context.
    table_list          Open first table in list.
2624 2625 2626 2627
    action       INOUT  Pointer to variable of enum_open_table_action type
                        which will be set according to action which is
                        required to remedy problem appeared during attempt
                        to open table.
2628
    flags               Bitmap of flags to modify how open works:
2629
                          MYSQL_OPEN_IGNORE_FLUSH - Open table even if
2630 2631 2632
                          someone has done a flush or there is a pending
                          exclusive metadata lock requests against it
                          (i.e. request high priority metadata lock).
2633
                          No version number checking is done.
unknown's avatar
unknown committed
2634 2635
                          MYSQL_OPEN_TEMPORARY_ONLY - Open only temporary
                          table not the base table or view.
Konstantin Osipov's avatar
Konstantin Osipov committed
2636 2637 2638
                          MYSQL_OPEN_TAKE_UPGRADABLE_MDL - Obtain upgradable
                          metadata lock for tables on which we are going to
                          take some kind of write table-level lock.
2639 2640 2641 2642

  IMPLEMENTATION
    Uses a cache of open tables to find a table not in use.

2643 2644 2645 2646 2647
    If TABLE_LIST::open_strategy is set to OPEN_IF_EXISTS, the table is opened
    only if it exists. If the open strategy is OPEN_STUB, the underlying table
    is never opened. In both cases, metadata locks are always taken according
    to the lock strategy.

2648
  RETURN
Konstantin Osipov's avatar
Konstantin Osipov committed
2649 2650 2651 2652 2653
    TRUE  Open failed. "action" parameter may contain type of action
          needed to remedy problem before retrying again.
    FALSE Success. Members of TABLE_LIST structure are filled properly (e.g.
          TABLE_LIST::table is set for real tables and TABLE_LIST::view is
          set for views).
2654
*/
unknown's avatar
unknown committed
2655 2656


Konstantin Osipov's avatar
Konstantin Osipov committed
2657
bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
2658
                Open_table_context *ot_ctx)
unknown's avatar
unknown committed
2659 2660 2661 2662
{
  reg1	TABLE *table;
  char	key[MAX_DBKEY_LENGTH];
  uint	key_length;
unknown's avatar
VIEW  
unknown committed
2663
  char	*alias= table_list->alias;
2664
  uint flags= ot_ctx->get_flags();
Konstantin Osipov's avatar
Konstantin Osipov committed
2665
  MDL_ticket *mdl_ticket;
2666 2667
  int error;
  TABLE_SHARE *share;
2668
  my_hash_value_type hash_value;
unknown's avatar
unknown committed
2669 2670
  DBUG_ENTER("open_table");

2671
  /* an open table operation needs a lot of the stack space */
2672
  if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (uchar *)&alias))
Konstantin Osipov's avatar
Konstantin Osipov committed
2673
    DBUG_RETURN(TRUE);
2674

unknown's avatar
unknown committed
2675
  if (thd->killed)
Konstantin Osipov's avatar
Konstantin Osipov committed
2676
    DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
2677 2678 2679

  key_length= (create_table_def_key(thd, key, table_list, 1) -
               TMP_TABLE_KEY_EXTRA);
2680

2681 2682 2683 2684 2685 2686 2687
  /*
    Unless requested otherwise, try to resolve this table in the list
    of temporary tables of this thread. In MySQL temporary tables
    are always thread-local and "shadow" possible base tables with the
    same name. This block implements the behaviour.
    TODO: move this block into a separate function.
  */
2688 2689
  if (table_list->open_type != OT_BASE_ONLY &&
      ! (flags & MYSQL_OPEN_SKIP_TEMPORARY))
unknown's avatar
unknown committed
2690
  {
unknown's avatar
VIEW  
unknown committed
2691
    for (table= thd->temporary_tables; table ; table=table->next)
unknown's avatar
unknown committed
2692
    {
unknown's avatar
unknown committed
2693 2694 2695
      if (table->s->table_cache_key.length == key_length +
          TMP_TABLE_KEY_EXTRA &&
	  !memcmp(table->s->table_cache_key.str, key,
unknown's avatar
unknown committed
2696
		  key_length + TMP_TABLE_KEY_EXTRA))
unknown's avatar
unknown committed
2697
      {
2698 2699 2700 2701 2702 2703
        /*
          We're trying to use the same temporary table twice in a query.
          Right now we don't support this because a temporary table
          is always represented by only one TABLE object in THD, and
          it can not be cloned. Emit an error for an unsupported behaviour.
        */
2704
	if (table->query_id)
unknown's avatar
VIEW  
unknown committed
2705
	{
unknown's avatar
unknown committed
2706 2707 2708 2709
          DBUG_PRINT("error",
                     ("query_id: %lu  server_id: %u  pseudo_thread_id: %lu",
                      (ulong) table->query_id, (uint) thd->server_id,
                      (ulong) thd->variables.pseudo_thread_id));
2710
	  my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
Konstantin Osipov's avatar
Konstantin Osipov committed
2711
	  DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
2712 2713
	}
	table->query_id= thd->query_id;
unknown's avatar
unknown committed
2714
	thd->thread_specific_used= TRUE;
unknown's avatar
unknown committed
2715 2716
        DBUG_PRINT("info",("Using temporary table"));
        goto reset;
unknown's avatar
unknown committed
2717 2718 2719 2720
      }
    }
  }

2721 2722
  if (table_list->open_type == OT_TEMPORARY_ONLY ||
      (flags & MYSQL_OPEN_TEMPORARY_ONLY))
unknown's avatar
unknown committed
2723
  {
2724 2725 2726 2727 2728 2729 2730
    if (table_list->open_strategy == TABLE_LIST::OPEN_NORMAL)
    {
      my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name);
      DBUG_RETURN(TRUE);
    }
    else
      DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
2731 2732
  }

2733 2734 2735 2736 2737 2738 2739
  /*
    The table is not temporary - if we're in pre-locked or LOCK TABLES
    mode, let's try to find the requested table in the list of pre-opened
    and locked tables. If the table is not there, return an error - we can't
    open not pre-opened tables in pre-locked/LOCK TABLES mode.
    TODO: move this block into a separate function.
  */
Konstantin Osipov's avatar
Konstantin Osipov committed
2740 2741
  if (thd->locked_tables_mode &&
      ! (flags & MYSQL_OPEN_GET_NEW_TABLE))
unknown's avatar
unknown committed
2742
  {						// Using table locks
2743
    TABLE *best_table= 0;
unknown's avatar
unknown committed
2744
    int best_distance= INT_MIN;
unknown's avatar
unknown committed
2745 2746
    for (table=thd->open_tables; table ; table=table->next)
    {
unknown's avatar
unknown committed
2747 2748
      if (table->s->table_cache_key.length == key_length &&
	  !memcmp(table->s->table_cache_key.str, key, key_length))
unknown's avatar
unknown committed
2749
      {
2750 2751
        if (!my_strcasecmp(system_charset_info, table->alias, alias) &&
            table->query_id != thd->query_id && /* skip tables already used */
Konstantin Osipov's avatar
Konstantin Osipov committed
2752
            (thd->locked_tables_mode == LTM_LOCK_TABLES ||
Konstantin Osipov's avatar
Konstantin Osipov committed
2753
             table->query_id == 0))
2754 2755 2756
        {
          int distance= ((int) table->reginfo.lock_type -
                         (int) table_list->lock_type);
2757

2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769
          /*
            Find a table that either has the exact lock type requested,
            or has the best suitable lock. In case there is no locked
            table that has an equal or higher lock than requested,
            we us the closest matching lock to be able to produce an error
            message about wrong lock mode on the table. The best_table
            is changed if bd < 0 <= d or bd < d < 0 or 0 <= d < bd.

            distance <  0 - No suitable lock found
            distance >  0 - we have lock mode higher then we require
            distance == 0 - we have lock mode exactly which we need
          */
2770 2771
          if ((best_distance < 0 && distance > best_distance) ||
              (distance >= 0 && distance < best_distance))
2772 2773 2774
          {
            best_distance= distance;
            best_table= table;
2775
            if (best_distance == 0)
2776 2777
            {
              /*
2778 2779 2780 2781
                We have found a perfect match and can finish iterating
                through open tables list. Check for table use conflict
                between calling statement and SP/trigger is done in
                lock_tables().
2782 2783 2784 2785
              */
              break;
            }
          }
2786
        }
unknown's avatar
unknown committed
2787
      }
unknown's avatar
unknown committed
2788
    }
2789 2790 2791 2792 2793 2794 2795
    if (best_table)
    {
      table= best_table;
      table->query_id= thd->query_id;
      DBUG_PRINT("info",("Using locked table"));
      goto reset;
    }
unknown's avatar
unknown committed
2796
    /*
2797
      Is this table a view and not a base table?
unknown's avatar
unknown committed
2798 2799
      (it is work around to allow to open view with locked tables,
      real fix will be made after definition cache will be made)
2800 2801 2802 2803

      Since opening of view which was not explicitly locked by LOCK
      TABLES breaks metadata locking protocol (potentially can lead
      to deadlocks) it should be disallowed.
unknown's avatar
unknown committed
2804
    */
2805 2806 2807 2808
    if (thd->mdl_context.is_lock_owner(MDL_key::TABLE,
                                       table_list->db,
                                       table_list->table_name,
                                       MDL_SHARED))
unknown's avatar
unknown committed
2809
    {
2810
      char path[FN_REFLEN + 1];
unknown's avatar
unknown committed
2811
      enum legacy_db_type not_used;
2812
      build_table_filename(path, sizeof(path) - 1,
2813
                           table_list->db, table_list->table_name, reg_ext, 0);
Konstantin Osipov's avatar
Konstantin Osipov committed
2814 2815 2816 2817 2818 2819 2820
      /*
        Note that we can't be 100% sure that it is a view since it's
        possible that we either simply have not found unused TABLE
        instance in THD::open_tables list or were unable to open table
        during prelocking process (in this case in theory we still
        should hold shared metadata lock on it).
      */
2821
      if (dd_frm_type(thd, path, &not_used) == FRMTYPE_VIEW)
unknown's avatar
unknown committed
2822
      {
2823 2824
        if (!tdc_open_view(thd, table_list, alias, key, key_length,
                           mem_root, 0))
unknown's avatar
unknown committed
2825
        {
2826
          DBUG_ASSERT(table_list->view != 0);
Konstantin Osipov's avatar
Konstantin Osipov committed
2827
          DBUG_RETURN(FALSE); // VIEW
unknown's avatar
unknown committed
2828 2829 2830
        }
      }
    }
2831 2832 2833 2834 2835 2836 2837
    /*
      No table in the locked tables list. In case of explicit LOCK TABLES
      this can happen if a user did not include the able into the list.
      In case of pre-locked mode locked tables list is generated automatically,
      so we may only end up here if the table did not exist when
      locked tables list was created.
    */
Konstantin Osipov's avatar
Konstantin Osipov committed
2838
    if (thd->locked_tables_mode == LTM_PRELOCKED)
Konstantin Osipov's avatar
Konstantin Osipov committed
2839 2840 2841 2842 2843
      my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
    else
      my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
    DBUG_RETURN(TRUE);
  }
Konstantin Osipov's avatar
Konstantin Osipov committed
2844

Konstantin Osipov's avatar
Konstantin Osipov committed
2845 2846 2847 2848
  /*
    Non pre-locked/LOCK TABLES mode, and the table is not temporary.
    This is the normal use case.
  */
Konstantin Osipov's avatar
Konstantin Osipov committed
2849

Konstantin Osipov's avatar
Konstantin Osipov committed
2850 2851
  if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK))
  {
2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904
    /*
      We are not under LOCK TABLES and going to acquire write-lock/
      modify the base table. We need to acquire protection against
      global read lock until end of this statement in order to have
      this statement blocked by active FLUSH TABLES WITH READ LOCK.

      We don't block acquire this protection under LOCK TABLES as
      such protection already acquired at LOCK TABLES time and
      not released until UNLOCK TABLES.

      We don't block statements which modify only temporary tables
      as these tables are not preserved by backup by any form of
      backup which uses FLUSH TABLES WITH READ LOCK.

      TODO: The fact that we sometimes acquire protection against
            GRL only when we encounter table to be write-locked
            slightly increases probability of deadlock.
            This problem will be solved once Alik pushes his
            temporary table refactoring patch and we can start
            pre-acquiring metadata locks at the beggining of
            open_tables() call.
    */
    if (table_list->mdl_request.type >= MDL_SHARED_WRITE &&
        ! (flags & (MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |
                    MYSQL_OPEN_FORCE_SHARED_MDL |
                    MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
                    MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)) &&
        ! ot_ctx->has_protection_against_grl())
    {
      MDL_request protection_request;
      MDL_deadlock_handler mdl_deadlock_handler(ot_ctx);

      if (thd->global_read_lock.can_acquire_protection())
        DBUG_RETURN(TRUE);

      protection_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
                              MDL_STATEMENT);

      /*
        Install error handler which if possible will convert deadlock error
        into request to back-off and restart process of opening tables.
      */
      thd->push_internal_handler(&mdl_deadlock_handler);
      bool result= thd->mdl_context.acquire_lock(&protection_request,
                                                 ot_ctx->get_timeout());
      thd->pop_internal_handler();

      if (result)
        DBUG_RETURN(TRUE);

      ot_ctx->set_has_protection_against_grl();
    }

2905 2906 2907
    if (open_table_get_mdl_lock(thd, ot_ctx, &table_list->mdl_request,
                                flags, &mdl_ticket) ||
        mdl_ticket == NULL)
Konstantin Osipov's avatar
Konstantin Osipov committed
2908 2909
    {
      DEBUG_SYNC(thd, "before_open_table_wait_refresh");
Konstantin Osipov's avatar
Konstantin Osipov committed
2910
      DBUG_RETURN(TRUE);
Konstantin Osipov's avatar
Konstantin Osipov committed
2911 2912
    }
    DEBUG_SYNC(thd, "after_open_table_mdl_shared");
2913
  }
2914 2915 2916 2917 2918 2919 2920 2921
  else
  {
    /*
      Grab reference to the MDL lock ticket that was acquired
      by the caller.
    */
    mdl_ticket= table_list->mdl_request.ticket;
  }
Konstantin Osipov's avatar
Konstantin Osipov committed
2922

2923
  hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
unknown's avatar
unknown committed
2924 2925


2926
  if (table_list->open_strategy == TABLE_LIST::OPEN_IF_EXISTS)
unknown's avatar
unknown committed
2927
  {
2928
    bool exists;
2929

2930
    if (check_if_table_exists(thd, table_list, &exists))
2931
      DBUG_RETURN(TRUE);
2932

2933
    if (!exists)
Konstantin Osipov's avatar
Konstantin Osipov committed
2934
      DBUG_RETURN(FALSE);
2935

2936 2937
    /* Table exists. Let us try to open it. */
  }
2938
  else if (table_list->open_strategy == TABLE_LIST::OPEN_STUB)
Konstantin Osipov's avatar
Konstantin Osipov committed
2939
    DBUG_RETURN(FALSE);
unknown's avatar
unknown committed
2940

2941 2942
retry_share:

2943
  mysql_mutex_lock(&LOCK_open);
2944

2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963
  if (!(share= get_table_share_with_discover(thd, table_list, key,
                                             key_length, OPEN_VIEW,
                                             &error,
                                             hash_value)))
  {
    mysql_mutex_unlock(&LOCK_open);
    /*
      If thd->is_error() is not set, we either need discover
      (error == 7), or the error was silenced by the prelocking
      handler (error == 0), in which case we should skip this
      table.
    */
    if (error == 7 && !thd->is_error())
    {
      (void) ot_ctx->request_backoff_action(Open_table_context::OT_DISCOVER,
                                            table_list);
    }
    DBUG_RETURN(TRUE);
  }
2964

2965 2966
  if (share->is_view)
  {
2967
    /*
2968 2969
      If parent_l of the table_list is non null then a merge table
      has this view as child table, which is not supported.
2970
    */
2971
    if (table_list->parent_l)
2972
    {
2973 2974
      my_error(ER_WRONG_MRG_TABLE, MYF(0));
      goto err_unlock;
unknown's avatar
unknown committed
2975
    }
2976 2977

    /*
2978 2979
      This table is a view. Validate its metadata version: in particular,
      that it was a view when the statement was prepared.
2980
    */
2981 2982
    if (check_and_update_table_version(thd, table_list, share))
      goto err_unlock;
2983 2984 2985 2986
    if (table_list->i_s_requested_object & OPEN_TABLE_ONLY)
    {
      my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db,
               table_list->table_name);
2987
      goto err_unlock;
2988
    }
2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005

    /* Open view */
    if (open_new_frm(thd, share, alias,
                     (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
                             HA_GET_INDEX | HA_TRY_READ_ONLY),
                     READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
                     thd->open_options,
                     0, table_list, mem_root))
      goto err_unlock;

    /* TODO: Don't free this */
    release_table_share(share);

    DBUG_ASSERT(table_list->view);

    mysql_mutex_unlock(&LOCK_open);
    DBUG_RETURN(FALSE);
3006 3007
  }

3008 3009 3010 3011 3012 3013 3014 3015
  /*
    Note that situation when we are trying to open a table for what
    was a view during previous execution of PS will be handled in by
    the caller. Here we should simply open our table even if
    TABLE_LIST::view is true.
  */

  if (table_list->i_s_requested_object &  OPEN_VIEW_ONLY)
3016 3017 3018
  {
    my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db,
             table_list->table_name);
3019
    goto err_unlock;
3020
  }
3021

3022
  if (!(flags & MYSQL_OPEN_IGNORE_FLUSH))
3023
  {
3024
    if (share->has_old_version())
3025
    {
3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038
      /*
        We already have an MDL lock. But we have encountered an old
        version of table in the table definition cache which is possible
        when someone changes the table version directly in the cache
        without acquiring a metadata lock (e.g. this can happen during
        "rolling" FLUSH TABLE(S)).
        Release our reference to share, wait until old version of
        share goes away and then try to get new version of table share.
      */
      MDL_deadlock_handler mdl_deadlock_handler(ot_ctx);
      bool wait_result;

      release_table_share(share);
3039
      mysql_mutex_unlock(&LOCK_open);
3040 3041

      thd->push_internal_handler(&mdl_deadlock_handler);
3042 3043
      wait_result= tdc_wait_for_old_version(thd, table_list->db,
                                            table_list->table_name,
3044 3045 3046 3047 3048 3049
                                            ot_ctx->get_timeout(),
                                            mdl_ticket->get_deadlock_weight());
      thd->pop_internal_handler();

      if (wait_result)
        DBUG_RETURN(TRUE);
3050

3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061
      goto retry_share;
    }

    if (thd->open_tables && thd->open_tables->s->version != share->version)
    {
      /*
        If the version changes while we're opening the tables,
        we have to back off, close all the tables opened-so-far,
        and try to reopen them. Note: refresh_version is currently
        changed only during FLUSH TABLES.
      */
Konstantin Osipov's avatar
Konstantin Osipov committed
3062
      release_table_share(share);
3063
      mysql_mutex_unlock(&LOCK_open);
3064 3065
      (void)ot_ctx->request_backoff_action(Open_table_context::OT_REOPEN_TABLES,
                                           NULL);
Konstantin Osipov's avatar
Konstantin Osipov committed
3066
      DBUG_RETURN(TRUE);
3067 3068 3069 3070 3071
    }
  }

  if (!share->free_tables.is_empty())
  {
3072
    table= share->free_tables.front();
3073 3074
    table_def_use_table(thd, table);
    /* We need to release share as we have EXTRA reference to it in our hands. */
Konstantin Osipov's avatar
Konstantin Osipov committed
3075
    release_table_share(share);
unknown's avatar
unknown committed
3076 3077 3078
  }
  else
  {
3079 3080 3081
    /* We have too many TABLE instances around let us try to get rid of them. */
    while (table_cache_count > table_cache_size && unused_tables)
      free_cache_entry(unused_tables);
unknown's avatar
unknown committed
3082

3083 3084
    mysql_mutex_unlock(&LOCK_open);

3085 3086
    /* make a new table */
    if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME))))
3087
      goto err_lock;
unknown's avatar
unknown committed
3088

3089 3090 3091 3092 3093 3094 3095 3096
    error= open_table_from_share(thd, share, alias,
                                 (uint) (HA_OPEN_KEYFILE |
                                         HA_OPEN_RNDFILE |
                                         HA_GET_INDEX |
                                         HA_TRY_READ_ONLY),
                                 (READ_KEYINFO | COMPUTE_TYPES |
                                  EXTRA_RECORD),
                                 thd->open_options, table, FALSE);
unknown's avatar
unknown committed
3097

3098 3099
    if (error)
    {
3100
      my_free(table);
3101

Konstantin Osipov's avatar
Konstantin Osipov committed
3102
      if (error == 7)
3103
        (void) ot_ctx->request_backoff_action(Open_table_context::OT_DISCOVER,
3104
                                              table_list);
Konstantin Osipov's avatar
Konstantin Osipov committed
3105
      else if (share->crashed)
3106
        (void) ot_ctx->request_backoff_action(Open_table_context::OT_REPAIR,
3107
                                              table_list);
unknown's avatar
unknown committed
3108

3109
      goto err_lock;
3110
    }
unknown's avatar
unknown committed
3111

3112
    if (open_table_entry_fini(thd, share, table))
unknown's avatar
unknown committed
3113
    {
3114
      closefrm(table, 0);
3115
      my_free(table);
3116
      goto err_lock;
unknown's avatar
unknown committed
3117
    }
3118

3119
    mysql_mutex_lock(&LOCK_open);
3120 3121
    /* Add table to the share's used tables list. */
    table_def_add_used_table(thd, table);
unknown's avatar
unknown committed
3122 3123
  }

Marc Alff's avatar
Marc Alff committed
3124
  mysql_mutex_unlock(&LOCK_open);
3125

Konstantin Osipov's avatar
Konstantin Osipov committed
3126
  table->mdl_ticket= mdl_ticket;
Konstantin Osipov's avatar
Konstantin Osipov committed
3127

3128 3129
  table->next= thd->open_tables;		/* Link into simple list */
  thd->set_open_tables(table);
Konstantin Osipov's avatar
Konstantin Osipov committed
3130

unknown's avatar
unknown committed
3131 3132 3133
  table->reginfo.lock_type=TL_READ;		/* Assume read */

 reset:
3134 3135 3136 3137 3138
  /*
    Check that there is no reference to a condtion from an earlier query
    (cf. Bug#58553). 
  */
  DBUG_ASSERT(table->file->pushed_cond == NULL);
unknown's avatar
VIEW  
unknown committed
3139
  table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
Konstantin Osipov's avatar
Konstantin Osipov committed
3140
  table_list->table= table;
3141 3142 3143

  table->init(thd, table_list);

Konstantin Osipov's avatar
Konstantin Osipov committed
3144
  DBUG_RETURN(FALSE);
3145

3146 3147
err_lock:
  mysql_mutex_lock(&LOCK_open);
3148
err_unlock:
Konstantin Osipov's avatar
Konstantin Osipov committed
3149
  release_table_share(share);
3150
  mysql_mutex_unlock(&LOCK_open);
Konstantin Osipov's avatar
Konstantin Osipov committed
3151

Konstantin Osipov's avatar
Konstantin Osipov committed
3152
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
3153 3154 3155
}


3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166
/**
   Find table in the list of open tables.

   @param list       List of TABLE objects to be inspected.
   @param db         Database name
   @param table_name Table name

   @return Pointer to the TABLE object found, 0 if no table found.
*/

TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name)
unknown's avatar
unknown committed
3167 3168 3169 3170
{
  char	key[MAX_DBKEY_LENGTH];
  uint key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;

3171
  for (TABLE *table= list; table ; table=table->next)
unknown's avatar
unknown committed
3172
  {
unknown's avatar
unknown committed
3173 3174
    if (table->s->table_cache_key.length == key_length &&
	!memcmp(table->s->table_cache_key.str, key, key_length))
unknown's avatar
unknown committed
3175 3176 3177 3178 3179 3180
      return table;
  }
  return(0);
}


3181
/**
3182 3183 3184
   Find instance of TABLE with upgradable or exclusive metadata
   lock from the list of open tables, emit error if no such table
   found.
3185

3186
   @param thd        Thread context
3187 3188
   @param db         Database name.
   @param table_name Name of table.
3189 3190
   @param no_error   Don't emit error if no suitable TABLE
                     instance were found.
3191

3192 3193 3194 3195 3196
   @note This function checks if the connection holds a global IX
         metadata lock. If no such lock is found, it is not safe to
         upgrade the lock and ER_TABLE_NOT_LOCKED_FOR_WRITE will be
         reported.

3197 3198 3199
   @return Pointer to TABLE instance with MDL_SHARED_NO_WRITE,
           MDL_SHARED_NO_READ_WRITE, or MDL_EXCLUSIVE metadata
           lock, NULL otherwise.
3200 3201
*/

3202 3203
TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,
                                  const char *table_name, bool no_error)
3204
{
3205
  TABLE *tab= find_locked_table(thd->open_tables, db, table_name);
3206 3207 3208

  if (!tab)
  {
3209 3210 3211
    if (!no_error)
      my_error(ER_TABLE_NOT_LOCKED, MYF(0), table_name);
    return NULL;
3212
  }
3213 3214 3215 3216 3217 3218 3219 3220 3221

  /*
    It is not safe to upgrade the metadata lock without a global IX lock.
    This can happen with FLUSH TABLES <list> WITH READ LOCK as we in these
    cases don't take a global IX lock in order to be compatible with
    global read lock.
  */
  if (!thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "",
                                      MDL_INTENTION_EXCLUSIVE))
3222
  {
3223 3224 3225
    if (!no_error)
      my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_name);
    return NULL;
3226
  }
3227 3228 3229 3230 3231 3232 3233 3234 3235

  while (tab->mdl_ticket != NULL &&
         !tab->mdl_ticket->is_upgradable_or_exclusive() &&
         (tab= find_locked_table(tab->next, db, table_name)))
    continue;

  if (!tab && !no_error)
    my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_name);

3236 3237 3238 3239
  return tab;
}


Konstantin Osipov's avatar
Konstantin Osipov committed
3240 3241 3242
/***********************************************************************
  class Locked_tables_list implementation. Declared in sql_class.h
************************************************************************/
unknown's avatar
unknown committed
3243

Konstantin Osipov's avatar
Konstantin Osipov committed
3244 3245
/**
  Enter LTM_LOCK_TABLES mode.
unknown's avatar
unknown committed
3246

Konstantin Osipov's avatar
Konstantin Osipov committed
3247 3248 3249
  Enter the LOCK TABLES mode using all the tables that are
  currently open and locked in this connection.
  Initializes a TABLE_LIST instance for every locked table.
unknown's avatar
unknown committed
3250

Konstantin Osipov's avatar
Konstantin Osipov committed
3251 3252 3253
  @param  thd  thread handle

  @return TRUE if out of memory.
unknown's avatar
unknown committed
3254 3255
*/

Konstantin Osipov's avatar
Konstantin Osipov committed
3256 3257
bool
Locked_tables_list::init_locked_tables(THD *thd)
unknown's avatar
unknown committed
3258
{
Konstantin Osipov's avatar
Konstantin Osipov committed
3259 3260
  DBUG_ASSERT(thd->locked_tables_mode == LTM_NONE);
  DBUG_ASSERT(m_locked_tables == NULL);
Konstantin Osipov's avatar
Konstantin Osipov committed
3261 3262
  DBUG_ASSERT(m_reopen_array == NULL);
  DBUG_ASSERT(m_locked_tables_count == 0);
Konstantin Osipov's avatar
Konstantin Osipov committed
3263

Konstantin Osipov's avatar
Konstantin Osipov committed
3264 3265
  for (TABLE *table= thd->open_tables; table;
       table= table->next, m_locked_tables_count++)
Konstantin Osipov's avatar
Konstantin Osipov committed
3266 3267 3268
  {
    TABLE_LIST *src_table_list= table->pos_in_table_list;
    char *db, *table_name, *alias;
Konstantin Osipov's avatar
Konstantin Osipov committed
3269 3270 3271
    size_t db_len= src_table_list->db_length;
    size_t table_name_len= src_table_list->table_name_length;
    size_t alias_len= strlen(src_table_list->alias);
Konstantin Osipov's avatar
Konstantin Osipov committed
3272 3273 3274 3275
    TABLE_LIST *dst_table_list;

    if (! multi_alloc_root(&m_locked_tables_root,
                           &dst_table_list, sizeof(*dst_table_list),
Konstantin Osipov's avatar
Konstantin Osipov committed
3276 3277 3278
                           &db, db_len + 1,
                           &table_name, table_name_len + 1,
                           &alias, alias_len + 1,
Konstantin Osipov's avatar
Konstantin Osipov committed
3279
                           NullS))
Konstantin Osipov's avatar
Konstantin Osipov committed
3280 3281 3282 3283 3284
    {
      unlock_locked_tables(0);
      return TRUE;
    }

Konstantin Osipov's avatar
Konstantin Osipov committed
3285 3286 3287
    memcpy(db, src_table_list->db, db_len + 1);
    memcpy(table_name, src_table_list->table_name, table_name_len + 1);
    memcpy(alias, src_table_list->alias, alias_len + 1);
Konstantin Osipov's avatar
Konstantin Osipov committed
3288 3289 3290 3291 3292 3293 3294
    /**
      Sic: remember the *actual* table level lock type taken, to
      acquire the exact same type in reopen_tables().
      E.g. if the table was locked for write, src_table_list->lock_type is
      TL_WRITE_DEFAULT, whereas reginfo.lock_type has been updated from
      thd->update_lock_default.
    */
Konstantin Osipov's avatar
Konstantin Osipov committed
3295 3296
    dst_table_list->init_one_table(db, db_len, table_name, table_name_len,
                                   alias,
Konstantin Osipov's avatar
Konstantin Osipov committed
3297 3298
                                   src_table_list->table->reginfo.lock_type);
    dst_table_list->table= table;
Konstantin Osipov's avatar
Konstantin Osipov committed
3299 3300
    dst_table_list->mdl_request.ticket= src_table_list->mdl_request.ticket;

Konstantin Osipov's avatar
Konstantin Osipov committed
3301 3302 3303 3304 3305
    /* Link last into the list of tables */
    *(dst_table_list->prev_global= m_locked_tables_last)= dst_table_list;
    m_locked_tables_last= &dst_table_list->next_global;
    table->pos_in_locked_tables= dst_table_list;
  }
Konstantin Osipov's avatar
Konstantin Osipov committed
3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321
  if (m_locked_tables_count)
  {
    /**
      Allocate an auxiliary array to pass to mysql_lock_tables()
      in reopen_tables(). reopen_tables() is a critical
      path and we don't want to complicate it with extra allocations.
    */
    m_reopen_array= (TABLE**)alloc_root(&m_locked_tables_root,
                                        sizeof(TABLE*) *
                                        (m_locked_tables_count+1));
    if (m_reopen_array == NULL)
    {
      unlock_locked_tables(0);
      return TRUE;
    }
  }
3322
  thd->enter_locked_tables_mode(LTM_LOCK_TABLES);
Konstantin Osipov's avatar
Konstantin Osipov committed
3323

Konstantin Osipov's avatar
Konstantin Osipov committed
3324 3325
  return FALSE;
}
unknown's avatar
unknown committed
3326

3327

Konstantin Osipov's avatar
Konstantin Osipov committed
3328 3329
/**
  Leave LTM_LOCK_TABLES mode if it's been entered.
unknown's avatar
unknown committed
3330

Konstantin Osipov's avatar
Konstantin Osipov committed
3331
  Close all locked tables, free memory, and leave the mode.
3332

Konstantin Osipov's avatar
Konstantin Osipov committed
3333 3334
  @note This function is a no-op if we're not in LOCK TABLES.
*/
unknown's avatar
unknown committed
3335

Konstantin Osipov's avatar
Konstantin Osipov committed
3336 3337
void
Locked_tables_list::unlock_locked_tables(THD *thd)
unknown's avatar
unknown committed
3338

Konstantin Osipov's avatar
Konstantin Osipov committed
3339 3340
{
  if (thd)
3341
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354
    DBUG_ASSERT(!thd->in_sub_stmt &&
                !(thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
    /*
      Sic: we must be careful to not close open tables if
      we're not in LOCK TABLES mode: unlock_locked_tables() is
      sometimes called implicitly, expecting no effect on
      open tables, e.g. from begin_trans().
    */
    if (thd->locked_tables_mode != LTM_LOCK_TABLES)
      return;

    for (TABLE_LIST *table_list= m_locked_tables;
         table_list; table_list= table_list->next_global)
3355
    {
Konstantin Osipov's avatar
Konstantin Osipov committed
3356 3357 3358 3359 3360
      /*
        Clear the position in the list, the TABLE object will be
        returned to the table cache.
      */
      table_list->table->pos_in_locked_tables= NULL;
3361
    }
3362
    thd->leave_locked_tables_mode();
Konstantin Osipov's avatar
Konstantin Osipov committed
3363

3364
    DBUG_ASSERT(thd->transaction.stmt.is_empty());
Konstantin Osipov's avatar
Konstantin Osipov committed
3365
    close_thread_tables(thd);
3366 3367 3368 3369
    /*
      We rely on the caller to implicitly commit the
      transaction and release transactional locks.
    */
3370
  }
3371
  /*
Konstantin Osipov's avatar
Konstantin Osipov committed
3372 3373
    After closing tables we can free memory used for storing lock
    request for metadata locks and TABLE_LIST elements.
3374
  */
Konstantin Osipov's avatar
Konstantin Osipov committed
3375 3376 3377
  free_root(&m_locked_tables_root, MYF(0));
  m_locked_tables= NULL;
  m_locked_tables_last= &m_locked_tables;
Konstantin Osipov's avatar
Konstantin Osipov committed
3378 3379
  m_reopen_array= NULL;
  m_locked_tables_count= 0;
unknown's avatar
unknown committed
3380 3381 3382
}


3383
/**
Konstantin Osipov's avatar
Konstantin Osipov committed
3384 3385 3386 3387 3388 3389 3390 3391 3392 3393
  Unlink a locked table from the locked tables list, either
  temporarily or permanently.

  @param  thd        thread handle
  @param  table_list the element of locked tables list.
                     The implementation assumes that this argument
                     points to a TABLE_LIST element linked into
                     the locked tables list. Passing a TABLE_LIST
                     instance that is not part of locked tables
                     list will lead to a crash.
Konstantin Osipov's avatar
Konstantin Osipov committed
3394
  @param  remove_from_locked_tables
Konstantin Osipov's avatar
Konstantin Osipov committed
3395 3396 3397 3398 3399 3400
                      TRUE if the table is removed from the list
                      permanently.

  This function is a no-op if we're not under LOCK TABLES.

  @sa Locked_tables_list::reopen_tables()
unknown's avatar
unknown committed
3401
*/
unknown's avatar
unknown committed
3402

Konstantin Osipov's avatar
Konstantin Osipov committed
3403 3404 3405 3406

void Locked_tables_list::unlink_from_list(THD *thd,
                                          TABLE_LIST *table_list,
                                          bool remove_from_locked_tables)
unknown's avatar
unknown committed
3407
{
Konstantin Osipov's avatar
Konstantin Osipov committed
3408 3409 3410 3411 3412 3413
  /*
    If mode is not LTM_LOCK_TABLES, we needn't do anything. Moreover,
    outside this mode pos_in_locked_tables value is not trustworthy.
  */
  if (thd->locked_tables_mode != LTM_LOCK_TABLES)
    return;
3414

Konstantin Osipov's avatar
Konstantin Osipov committed
3415 3416 3417 3418 3419
  /*
    table_list must be set and point to pos_in_locked_tables of some
    table.
  */
  DBUG_ASSERT(table_list->table->pos_in_locked_tables == table_list);
3420

Konstantin Osipov's avatar
Konstantin Osipov committed
3421 3422 3423 3424 3425
  /* Clear the pointer, the table will be returned to the table cache. */
  table_list->table->pos_in_locked_tables= NULL;

  /* Mark the table as closed in the locked tables list. */
  table_list->table= NULL;
unknown's avatar
unknown committed
3426

Konstantin Osipov's avatar
Konstantin Osipov committed
3427 3428 3429 3430 3431 3432
  /*
    If the table is being dropped or renamed, remove it from
    the locked tables list (implicitly drop the LOCK TABLES lock
    on it).
  */
  if (remove_from_locked_tables)
unknown's avatar
unknown committed
3433
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
3434 3435 3436 3437 3438
    *table_list->prev_global= table_list->next_global;
    if (table_list->next_global == NULL)
      m_locked_tables_last= table_list->prev_global;
    else
      table_list->next_global->prev_global= table_list->prev_global;
unknown's avatar
unknown committed
3439 3440 3441
  }
}

unknown's avatar
unknown committed
3442
/**
Konstantin Osipov's avatar
Konstantin Osipov committed
3443 3444 3445 3446
  This is an attempt to recover (somewhat) in case of an error.
  If we failed to reopen a closed table, let's unlink it from the
  list and forget about it. From a user perspective that would look
  as if the server "lost" the lock on one of the locked tables.
3447

Konstantin Osipov's avatar
Konstantin Osipov committed
3448
  @note This function is a no-op if we're not under LOCK TABLES.
3449 3450
*/

Konstantin Osipov's avatar
Konstantin Osipov committed
3451 3452
void Locked_tables_list::
unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count)
3453
{
Konstantin Osipov's avatar
Konstantin Osipov committed
3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480
  /* If we managed to take a lock, unlock tables and free the lock. */
  if (lock)
    mysql_unlock_tables(thd, lock);
  /*
    If a failure happened in reopen_tables(), we may have succeeded
    reopening some tables, but not all.
    This works when the connection was killed in mysql_lock_tables().
  */
  if (reopen_count)
  {
    while (reopen_count--)
    {
      /*
        When closing the table, we must remove it
        from thd->open_tables list.
        We rely on the fact that open_table() that was used
        in reopen_tables() always links the opened table
        to the beginning of the open_tables list.
      */
      DBUG_ASSERT(thd->open_tables == m_reopen_array[reopen_count]);

      thd->open_tables->pos_in_locked_tables->table= NULL;

      close_thread_table(thd, &thd->open_tables);
    }
  }
  /* Exclude all closed tables from the LOCK TABLES list. */
Konstantin Osipov's avatar
Konstantin Osipov committed
3481 3482
  for (TABLE_LIST *table_list= m_locked_tables; table_list; table_list=
       table_list->next_global)
3483
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
3484
    if (table_list->table == NULL)
3485
    {
Konstantin Osipov's avatar
Konstantin Osipov committed
3486 3487 3488 3489
      /* Unlink from list. */
      *table_list->prev_global= table_list->next_global;
      if (table_list->next_global == NULL)
        m_locked_tables_last= table_list->prev_global;
3490
      else
Konstantin Osipov's avatar
Konstantin Osipov committed
3491
        table_list->next_global->prev_global= table_list->prev_global;
3492 3493 3494 3495 3496
    }
  }
}


unknown's avatar
unknown committed
3497
/**
Konstantin Osipov's avatar
Konstantin Osipov committed
3498 3499
  Reopen the tables locked with LOCK TABLES and temporarily closed
  by a DDL statement or FLUSH TABLES.
unknown's avatar
unknown committed
3500

Konstantin Osipov's avatar
Konstantin Osipov committed
3501
  @note This function is a no-op if we're not under LOCK TABLES.
unknown's avatar
unknown committed
3502

Konstantin Osipov's avatar
Konstantin Osipov committed
3503 3504 3505 3506
  @return TRUE if an error reopening the tables. May happen in
               case of some fatal system error only, e.g. a disk
               corruption, out of memory or a serious bug in the
               locking.
unknown's avatar
unknown committed
3507 3508
*/

Konstantin Osipov's avatar
Konstantin Osipov committed
3509 3510
bool
Locked_tables_list::reopen_tables(THD *thd)
unknown's avatar
unknown committed
3511
{
3512
  Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
Konstantin Osipov's avatar
Konstantin Osipov committed
3513 3514 3515
  size_t reopen_count= 0;
  MYSQL_LOCK *lock;
  MYSQL_LOCK *merged_lock;
unknown's avatar
unknown committed
3516

Konstantin Osipov's avatar
Konstantin Osipov committed
3517 3518
  for (TABLE_LIST *table_list= m_locked_tables;
       table_list; table_list= table_list->next_global)
unknown's avatar
unknown committed
3519
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
3520 3521 3522 3523
    if (table_list->table)                      /* The table was not closed */
      continue;

    /* Links into thd->open_tables upon success */
3524
    if (open_table(thd, table_list, thd->mem_root, &ot_ctx))
unknown's avatar
unknown committed
3525
    {
Konstantin Osipov's avatar
Konstantin Osipov committed
3526
      unlink_all_closed_tables(thd, 0, reopen_count);
Konstantin Osipov's avatar
Konstantin Osipov committed
3527
      return TRUE;
unknown's avatar
unknown committed
3528
    }
Konstantin Osipov's avatar
Konstantin Osipov committed
3529 3530 3531
    table_list->table->pos_in_locked_tables= table_list;
    /* See also the comment on lock type in init_locked_tables(). */
    table_list->table->reginfo.lock_type= table_list->lock_type;
Konstantin Osipov's avatar
Konstantin Osipov committed
3532 3533 3534 3535 3536 3537

    DBUG_ASSERT(reopen_count < m_locked_tables_count);
    m_reopen_array[reopen_count++]= table_list->table;
  }
  if (reopen_count)
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
3538
    thd->in_lock_tables= 1;
Konstantin Osipov's avatar
Konstantin Osipov committed
3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550
    /*
      We re-lock all tables with mysql_lock_tables() at once rather
      than locking one table at a time because of the case
      reported in Bug#45035: when the same table is present
      in the list many times, thr_lock.c fails to grant READ lock
      on a table that is already locked by WRITE lock, even if
      WRITE lock is taken by the same thread. If READ and WRITE
      lock are passed to thr_lock.c in the same list, everything
      works fine. Patching legacy code of thr_lock.c is risking to
      break something else.
    */
    lock= mysql_lock_tables(thd, m_reopen_array, reopen_count,
3551
                            MYSQL_OPEN_REOPEN);
Konstantin Osipov's avatar
Konstantin Osipov committed
3552
    thd->in_lock_tables= 0;
Konstantin Osipov's avatar
Konstantin Osipov committed
3553 3554
    if (lock == NULL || (merged_lock=
                         mysql_lock_merge(thd->lock, lock)) == NULL)
3555
    {
Konstantin Osipov's avatar
Konstantin Osipov committed
3556 3557 3558
      unlink_all_closed_tables(thd, lock, reopen_count);
      if (! thd->killed)
        my_error(ER_LOCK_DEADLOCK, MYF(0));
Konstantin Osipov's avatar
Konstantin Osipov committed
3559
      return TRUE;
3560
    }
Konstantin Osipov's avatar
Konstantin Osipov committed
3561
    thd->lock= merged_lock;
unknown's avatar
unknown committed
3562
  }
Konstantin Osipov's avatar
Konstantin Osipov committed
3563
  return FALSE;
unknown's avatar
unknown committed
3564 3565
}

3566

3567
/*
3568
  Function to assign a new table map id to a table share.
3569 3570 3571

  PARAMETERS

3572
    share - Pointer to table share structure
3573

unknown's avatar
unknown committed
3574 3575 3576 3577 3578 3579 3580
  DESCRIPTION

    We are intentionally not checking that share->mutex is locked
    since this function should only be called when opening a table
    share and before it is entered into the table_def_cache (meaning
    that it cannot be fetched by another thread, even accidentally).

3581 3582
  PRE-CONDITION(S)

3583
    share is non-NULL
3584
    The LOCK_open mutex is locked.
3585 3586 3587

  POST-CONDITION(S)

3588 3589 3590
    share->table_map_id is given a value that with a high certainty is
    not used by any other table (the only case where a table id can be
    reused is on wrap-around, which means more than 4 billion table
3591 3592
    share opens have been executed while one table was open all the
    time).
3593

3594
    share->table_map_id is not ~0UL.
3595
 */
3596 3597
static ulong last_table_id= ~0UL;

3598
void assign_new_table_id(TABLE_SHARE *share)
3599 3600
{

3601
  DBUG_ENTER("assign_new_table_id");
3602 3603

  /* Preconditions */
3604
  DBUG_ASSERT(share != NULL);
Marc Alff's avatar
Marc Alff committed
3605
  mysql_mutex_assert_owner(&LOCK_open);
3606 3607

  ulong tid= ++last_table_id;                   /* get next id */
3608 3609 3610 3611
  /*
    There is one reserved number that cannot be used.  Remember to
    change this when 6-byte global table id's are introduced.
  */
3612
  if (unlikely(tid == ~0UL))
3613
    tid= ++last_table_id;
3614
  share->table_map_id= tid;
3615 3616 3617
  DBUG_PRINT("info", ("table_id=%lu", tid));

  /* Post conditions */
3618
  DBUG_ASSERT(share->table_map_id != ~0UL);
3619 3620 3621 3622

  DBUG_VOID_RETURN;
}

3623
#ifndef DBUG_OFF
3624
/* Cause a spurious statement reprepare for debug purposes. */
3625
static bool inject_reprepare(THD *thd)
3626 3627 3628 3629 3630 3631 3632 3633 3634
{
  if (thd->m_reprepare_observer && thd->stmt_arena->is_reprepared == FALSE)
  {
    thd->m_reprepare_observer->report_error(thd);
    return TRUE;
  }

  return FALSE;
}
3635
#endif
3636

unknown's avatar
unknown committed
3637 3638 3639 3640
/**
  Compare metadata versions of an element obtained from the table
  definition cache and its corresponding node in the parse tree.

3641
  @details If the new and the old values mismatch, invoke
unknown's avatar
unknown committed
3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655
  Metadata_version_observer.
  At prepared statement prepare, all TABLE_LIST version values are
  NULL and we always have a mismatch. But there is no observer set
  in THD, and therefore no error is reported. Instead, we update
  the value in the parse tree, effectively recording the original
  version.
  At prepared statement execute, an observer may be installed.  If
  there is a version mismatch, we push an error and return TRUE.

  For conventional execution (no prepared statements), the
  observer is never installed.

  @sa Execute_observer
  @sa check_prepared_statement() to see cases when an observer is installed
3656 3657
  @sa TABLE_LIST::is_table_ref_id_equal()
  @sa TABLE_SHARE::get_table_ref_id()
unknown's avatar
unknown committed
3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668

  @param[in]      thd         used to report errors
  @param[in,out]  tables      TABLE_LIST instance created by the parser
                              Metadata version information in this object
                              is updated upon success.
  @param[in]      table_share an element from the table definition cache

  @retval  TRUE  an error, which has been reported
  @retval  FALSE success, version in TABLE_LIST has been updated
*/

3669
static bool
unknown's avatar
unknown committed
3670 3671 3672
check_and_update_table_version(THD *thd,
                               TABLE_LIST *tables, TABLE_SHARE *table_share)
{
3673
  if (! tables->is_table_ref_id_equal(table_share))
unknown's avatar
unknown committed
3674
  {
3675 3676
    if (thd->m_reprepare_observer &&
        thd->m_reprepare_observer->report_error(thd))
unknown's avatar
unknown committed
3677 3678 3679 3680 3681 3682
    {
      /*
        Version of the table share is different from the
        previous execution of the prepared statement, and it is
        unacceptable for this SQLCOM. Error has been reported.
      */
3683
      DBUG_ASSERT(thd->is_error());
unknown's avatar
unknown committed
3684 3685
      return TRUE;
    }
3686
    /* Always maintain the latest version and type */
3687
    tables->set_table_ref_id(table_share);
unknown's avatar
unknown committed
3688
  }
3689

3690
  DBUG_EXECUTE_IF("reprepare_each_statement", return inject_reprepare(thd););
unknown's avatar
unknown committed
3691 3692 3693
  return FALSE;
}

3694

Konstantin Osipov's avatar
Konstantin Osipov committed
3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754
/**
  Compares versions of a stored routine obtained from the sp cache
  and the version used at prepare.

  @details If the new and the old values mismatch, invoke
  Metadata_version_observer.
  At prepared statement prepare, all Sroutine_hash_entry version values
  are NULL and we always have a mismatch. But there is no observer set
  in THD, and therefore no error is reported. Instead, we update
  the value in Sroutine_hash_entry, effectively recording the original
  version.
  At prepared statement execute, an observer may be installed.  If
  there is a version mismatch, we push an error and return TRUE.

  For conventional execution (no prepared statements), the
  observer is never installed.

  @param[in]      thd         used to report errors
  @param[in/out]  rt          pointer to stored routine entry in the
                              parse tree
  @param[in]      sp          pointer to stored routine cache entry.
                              Can be NULL if there is no such routine.
  @retval  TRUE  an error, which has been reported
  @retval  FALSE success, version in Sroutine_hash_entry has been updated
*/

static bool
check_and_update_routine_version(THD *thd, Sroutine_hash_entry *rt,
                                 sp_head *sp)
{
  ulong spc_version= sp_cache_version();
  /* sp is NULL if there is no such routine. */
  ulong version= sp ? sp->sp_cache_version() : spc_version;
  /*
    If the version in the parse tree is stale,
    or the version in the cache is stale and sp is not used,
    we need to reprepare.
    Sic: version != spc_version <--> sp is not NULL.
  */
  if (rt->m_sp_cache_version != version ||
      (version != spc_version && !sp->is_invoked()))
  {
    if (thd->m_reprepare_observer &&
        thd->m_reprepare_observer->report_error(thd))
    {
      /*
        Version of the sp cache is different from the
        previous execution of the prepared statement, and it is
        unacceptable for this SQLCOM. Error has been reported.
      */
      DBUG_ASSERT(thd->is_error());
      return TRUE;
    }
    /* Always maintain the latest cache version. */
    rt->m_sp_cache_version= version;
  }
  return FALSE;
}


3755 3756
/**
   Open view by getting its definition from disk (and table cache in future).
3757

3758 3759 3760 3761 3762 3763 3764
   @param thd               Thread handle
   @param table_list        TABLE_LIST with db, table_name & belong_to_view
   @param alias             Alias name
   @param cache_key         Key for table definition cache
   @param cache_key_length  Length of cache_key
   @param mem_root          Memory to be used for .frm parsing.
   @param flags             Flags which modify how we open the view
3765

3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777
   @todo This function is needed for special handling of views under
         LOCK TABLES. We probably should get rid of it in long term.

   @return FALSE if success, TRUE - otherwise.
*/

bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
                   char *cache_key, uint cache_key_length,
                   MEM_ROOT *mem_root, uint flags)
{
  TABLE not_used;
  int error;
3778
  my_hash_value_type hash_value;
3779 3780
  TABLE_SHARE *share;

3781 3782
  hash_value= my_calc_hash(&table_def_cache, (uchar*) cache_key,
                           cache_key_length);
3783
  mysql_mutex_lock(&LOCK_open);
3784

3785 3786 3787 3788
  if (!(share= get_table_share(thd, table_list, cache_key,
                               cache_key_length,
                               OPEN_VIEW, &error,
                               hash_value)))
3789 3790 3791 3792 3793 3794 3795 3796 3797 3798
    goto err;

  if (share->is_view &&
      !open_new_frm(thd, share, alias,
                    (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
                            HA_GET_INDEX | HA_TRY_READ_ONLY),
                    READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD |
                    flags, thd->open_options, &not_used, table_list,
                    mem_root))
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
3799
    release_table_share(share);
3800
    mysql_mutex_unlock(&LOCK_open);
3801 3802 3803 3804
    return FALSE;
  }

  my_error(ER_WRONG_OBJECT, MYF(0), share->db.str, share->table_name.str, "VIEW");
Konstantin Osipov's avatar
Konstantin Osipov committed
3805
  release_table_share(share);
3806
err:
3807
  mysql_mutex_unlock(&LOCK_open);
3808 3809 3810 3811 3812
  return TRUE;
}


/**
Konstantin Osipov's avatar
Konstantin Osipov committed
3813 3814
   Finalize the process of TABLE creation by loading table triggers
   and taking action if a HEAP table content was emptied implicitly.
3815 3816 3817 3818 3819 3820 3821 3822
*/

static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry)
{
  if (Table_triggers_list::check_n_load(thd, share->db.str,
                                        share->table_name.str, entry, 0))
    return TRUE;

unknown's avatar
unknown committed
3823 3824 3825 3826 3827 3828 3829 3830 3831 3832
  /*
    If we are here, there was no fatal error (but error may be still
    unitialized).
  */
  if (unlikely(entry->file->implicit_emptied))
  {
    entry->file->implicit_emptied= 0;
    if (mysql_bin_log.is_open())
    {
      char *query, *end;
unknown's avatar
unknown committed
3833 3834
      uint query_buf_size= 20 + share->db.length + share->table_name.length +1;
      if ((query= (char*) my_malloc(query_buf_size,MYF(MY_WME))))
unknown's avatar
unknown committed
3835
      {
3836
        /* this DELETE FROM is needed even with row-based binlogging */
unknown's avatar
unknown committed
3837
        end = strxmov(strmov(query, "DELETE FROM `"),
unknown's avatar
unknown committed
3838
                      share->db.str,"`.`",share->table_name.str,"`", NullS);
3839
        int errcode= query_error_code(thd, TRUE);
3840 3841
        if (thd->binlog_query(THD::STMT_QUERY_TYPE,
                              query, (ulong)(end-query),
3842
                              FALSE, FALSE, FALSE, errcode))
3843
        {
3844
          my_free(query);
3845 3846
          return TRUE;
        }
3847
        my_free(query);
unknown's avatar
unknown committed
3848 3849 3850 3851 3852 3853 3854 3855
      }
      else
      {
        /*
          As replication is maybe going to be corrupted, we need to warn the
          DBA on top of warning the client (which will automatically be done
          because of MYF(MY_WME) in my_malloc() above).
        */
unknown's avatar
unknown committed
3856 3857
        sql_print_error("When opening HEAP table, could not allocate memory "
                        "to write 'DELETE FROM `%s`.`%s`' to the binary log",
3858
                        share->db.str, share->table_name.str);
3859
        delete entry->triggers;
3860
        return TRUE;
unknown's avatar
unknown committed
3861 3862
      }
    }
unknown's avatar
unknown committed
3863
  }
3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878
  return FALSE;
}


/**
   Auxiliary routine which is used for performing automatical table repair.
*/

static bool auto_repair_table(THD *thd, TABLE_LIST *table_list)
{
  char	cache_key[MAX_DBKEY_LENGTH];
  uint	cache_key_length;
  TABLE_SHARE *share;
  TABLE *entry;
  int not_used;
3879
  bool result= TRUE;
3880
  my_hash_value_type hash_value;
3881 3882 3883 3884 3885

  cache_key_length= create_table_def_key(thd, cache_key, table_list, 0);

  thd->clear_error();

3886 3887
  hash_value= my_calc_hash(&table_def_cache, (uchar*) cache_key,
                           cache_key_length);
3888
  mysql_mutex_lock(&LOCK_open);
3889

3890 3891 3892 3893
  if (!(share= get_table_share(thd, table_list, cache_key,
                               cache_key_length,
                               OPEN_VIEW, &not_used,
                               hash_value)))
3894
    goto end_unlock;
3895 3896

  if (share->is_view)
3897 3898 3899 3900
  {
    release_table_share(share);
    goto end_unlock;
  }
3901 3902 3903

  if (!(entry= (TABLE*)my_malloc(sizeof(TABLE), MYF(MY_WME))))
  {
3904 3905
    release_table_share(share);
    goto end_unlock;
3906
  }
3907
  mysql_mutex_unlock(&LOCK_open);
unknown's avatar
unknown committed
3908

3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919
  if (open_table_from_share(thd, share, table_list->alias,
                            (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
                                    HA_GET_INDEX |
                                    HA_TRY_READ_ONLY),
                            READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
                            ha_open_options | HA_OPEN_FOR_REPAIR,
                            entry, FALSE) || ! entry->file ||
      (entry->file->is_crashed() && entry->file->ha_check_and_repair(thd)))
  {
    /* Give right error message */
    thd->clear_error();
Guilhem Bichot's avatar
Guilhem Bichot committed
3920
    my_error(ER_NOT_KEYFILE, MYF(0), share->table_name.str);
3921 3922 3923 3924 3925 3926 3927 3928 3929
    sql_print_error("Couldn't repair table: %s.%s", share->db.str,
                    share->table_name.str);
    if (entry->file)
      closefrm(entry, 0);
  }
  else
  {
    thd->clear_error();			// Clear error message
    closefrm(entry, 0);
3930
    result= FALSE;
3931
  }
3932
  my_free(entry);
3933

3934
  mysql_mutex_lock(&LOCK_open);
Konstantin Osipov's avatar
Konstantin Osipov committed
3935
  release_table_share(share);
3936 3937
  /* Remove the repaired share from the table cache. */
  tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
3938 3939
                   table_list->db, table_list->table_name,
                   TRUE);
3940
end_unlock:
3941
  mysql_mutex_unlock(&LOCK_open);
3942 3943 3944 3945
  return result;
}


Konstantin Osipov's avatar
Konstantin Osipov committed
3946 3947
/** Open_table_context */

3948
Open_table_context::Open_table_context(THD *thd, uint flags)
3949
  :m_failed_table(NULL),
3950
   m_start_of_statement_svp(thd->mdl_context.mdl_savepoint()),
3951 3952 3953 3954
   m_timeout(flags & MYSQL_LOCK_IGNORE_TIMEOUT ?
             LONG_TIMEOUT : thd->variables.lock_wait_timeout),
   m_flags(flags),
   m_action(OT_NO_ACTION),
3955 3956
   m_has_locks(thd->mdl_context.has_locks()),
   m_has_protection_against_grl(FALSE)
Konstantin Osipov's avatar
Konstantin Osipov committed
3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969
{}


/**
  Check if we can back-off and set back off action if we can.
  Otherwise report and return error.

  @retval  TRUE if back-off is impossible.
  @retval  FALSE if we can back off. Back off action has been set.
*/

bool
Open_table_context::
3970
request_backoff_action(enum_open_table_action action_arg,
3971
                       TABLE_LIST *table)
Konstantin Osipov's avatar
Konstantin Osipov committed
3972 3973
{
  /*
3974
    A back off action may be one of three kinds:
3975 3976 3977 3978 3979 3980 3981 3982

    * We met a broken table that needs repair, or a table that
      is not present on this MySQL server and needs re-discovery.
      To perform the action, we need an exclusive metadata lock on
      the table. Acquiring an X lock while holding other shared
      locks is very deadlock-prone. If this is a multi- statement
      transaction that holds metadata locks for completed
      statements, we don't do it, and report an error instead.
3983
      The action type in this case is OT_DISCOVER or OT_REPAIR.
3984 3985 3986
    * Our attempt to acquire an MDL lock lead to a deadlock,
      detected by the MDL deadlock detector. The current
      session was chosen a victim. If this is a multi-statement
3987 3988 3989 3990 3991
      transaction that holds metadata locks taken by completed
      statements, restarting locking for the current statement
      may lead to a livelock. Releasing locks of completed
      statements can not be done as will lead to violation
      of ACID. Thus, again, if m_has_locks is set,
3992 3993 3994 3995
      we report an error. Otherwise, when there are no metadata
      locks other than which belong to this statement, we can
      try to recover from error by releasing all locks and
      restarting the pre-locking.
3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021
      Similarly, a deadlock error can occur when the
      pre-locking process met a TABLE_SHARE that is being
      flushed, and unsuccessfully waited for the flush to
      complete. A deadlock in this case can happen, e.g.,
      when our session is holding a metadata lock that
      is being waited on by a session which is using
      the table which is being flushed. The only way
      to recover from this error is, again, to close all
      open tables, release all locks, and retry pre-locking.
      Action type name is OT_REOPEN_TABLES. Re-trying
      while holding some locks may lead to a livelock,
      and thus we don't do it.
    * Finally, this session has open TABLEs from different
      "generations" of the table cache. This can happen, e.g.,
      when, after this session has successfully opened one
      table used for a statement, FLUSH TABLES interfered and
      expelled another table used in it. FLUSH TABLES then
      blocks and waits on the table already opened by this
      statement.
      We detect this situation by ensuring that table cache
      version of all tables used in a statement is the same.
      If it isn't, all tables needs to be reopened.
      Note, that we can always perform a reopen in this case,
      even if we already have metadata locks, since we don't
      keep tables open between statements and a livelock
      is not possible.
Konstantin Osipov's avatar
Konstantin Osipov committed
4022
  */
4023
  if (action_arg != OT_REOPEN_TABLES && m_has_locks)
Konstantin Osipov's avatar
Konstantin Osipov committed
4024 4025 4026 4027
  {
    my_error(ER_LOCK_DEADLOCK, MYF(0));
    return TRUE;
  }
4028 4029 4030 4031
  /*
    If auto-repair or discovery are requested, a pointer to table
    list element must be provided.
  */
4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044
  if (table)
  {
    DBUG_ASSERT(action_arg == OT_DISCOVER || action_arg == OT_REPAIR);
    m_failed_table= (TABLE_LIST*) current_thd->alloc(sizeof(TABLE_LIST));
    if (m_failed_table == NULL)
      return TRUE;
    m_failed_table->init_one_table(table->db, table->db_length,
                                   table->table_name,
                                   table->table_name_length,
                                   table->alias, TL_WRITE);
    m_failed_table->mdl_request.set_type(MDL_EXCLUSIVE);
  }
  m_action= action_arg;
Konstantin Osipov's avatar
Konstantin Osipov committed
4045 4046 4047 4048
  return FALSE;
}


4049
/**
Konstantin Osipov's avatar
Konstantin Osipov committed
4050
   Recover from failed attempt of open table by performing requested action.
4051 4052 4053

   @param  thd     Thread context

Konstantin Osipov's avatar
Konstantin Osipov committed
4054 4055
   @pre This function should be called only with "action" != OT_NO_ACTION
        and after having called @sa close_tables_for_reopen().
Konstantin Osipov's avatar
Konstantin Osipov committed
4056

4057 4058 4059 4060
   @retval FALSE - Success. One should try to open tables once again.
   @retval TRUE  - Error
*/

Konstantin Osipov's avatar
Konstantin Osipov committed
4061 4062
bool
Open_table_context::
4063
recover_from_failed_open(THD *thd)
4064 4065
{
  bool result= FALSE;
Konstantin Osipov's avatar
Konstantin Osipov committed
4066 4067
  /* Execute the action. */
  switch (m_action)
4068
  {
4069
    case OT_BACKOFF_AND_RETRY:
4070
      break;
4071
    case OT_REOPEN_TABLES:
4072 4073
      break;
    case OT_DISCOVER:
Konstantin Osipov's avatar
Konstantin Osipov committed
4074
      {
4075 4076 4077
        if ((result= lock_table_names(thd, m_failed_table, NULL,
                                      get_timeout(),
                                      MYSQL_OPEN_SKIP_TEMPORARY)))
Konstantin Osipov's avatar
Konstantin Osipov committed
4078
          break;
Konstantin Osipov's avatar
Konstantin Osipov committed
4079

4080
        tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
4081
                         m_failed_table->table_name, FALSE);
4082 4083
        ha_create_table_from_engine(thd, m_failed_table->db,
                                    m_failed_table->table_name);
Konstantin Osipov's avatar
Konstantin Osipov committed
4084 4085 4086

        thd->warning_info->clear_warning_info(thd->query_id);
        thd->clear_error();                 // Clear error message
4087
        thd->mdl_context.release_transactional_locks();
Konstantin Osipov's avatar
Konstantin Osipov committed
4088
        break;
Konstantin Osipov's avatar
Konstantin Osipov committed
4089
      }
4090
    case OT_REPAIR:
Konstantin Osipov's avatar
Konstantin Osipov committed
4091
      {
4092 4093 4094
        if ((result= lock_table_names(thd, m_failed_table, NULL,
                                      get_timeout(),
                                      MYSQL_OPEN_SKIP_TEMPORARY)))
Konstantin Osipov's avatar
Konstantin Osipov committed
4095
          break;
4096

4097
        tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
4098
                         m_failed_table->table_name, FALSE);
Konstantin Osipov's avatar
Konstantin Osipov committed
4099

4100
        result= auto_repair_table(thd, m_failed_table);
4101
        thd->mdl_context.release_transactional_locks();
Konstantin Osipov's avatar
Konstantin Osipov committed
4102 4103
        break;
      }
4104 4105 4106
    default:
      DBUG_ASSERT(0);
  }
4107 4108 4109 4110 4111 4112
  /*
    Reset the pointers to conflicting MDL request and the
    TABLE_LIST element, set when we need auto-discovery or repair,
    for safety.
  */
  m_failed_table= NULL;
4113 4114 4115 4116 4117 4118
  /*
    Reset flag indicating that we have already acquired protection
    against GRL. It is no longer valid as the corresponding lock was
    released by close_tables_for_reopen().
  */
  m_has_protection_against_grl= FALSE;
Konstantin Osipov's avatar
Konstantin Osipov committed
4119 4120
  /* Prepare for possible another back-off. */
  m_action= OT_NO_ACTION;
4121
  return result;
unknown's avatar
unknown committed
4122 4123
}

4124

4125 4126 4127 4128
/*
  Return a appropriate read lock type given a table object.

  @param thd Thread context
4129 4130
  @param prelocking_ctx Prelocking context.
  @param table_list     Table list element for table to be locked.
4131 4132 4133 4134 4135 4136 4137 4138

  @remark Due to a statement-based replication limitation, statements such as
          INSERT INTO .. SELECT FROM .. and CREATE TABLE .. SELECT FROM need
          to grab a TL_READ_NO_INSERT lock on the source table in order to
          prevent the replication of a concurrent statement that modifies the
          source table. If such a statement gets applied on the slave before
          the INSERT .. SELECT statement finishes, data on the master could
          differ from data on the slave and end-up with a discrepancy between
4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150
          the binary log and table state.
          This also applies to SELECT/SET/DO statements which use stored
          functions. Calls to such functions are going to be logged as a
          whole and thus should be serialized against concurrent changes
          to tables used by those functions. This can be avoided if functions
          only read data but doing so requires more complex analysis than it
          is done now.
          Furthermore, this does not apply to I_S and log tables as it's
          always unsafe to replicate such tables under statement-based
          replication as the table on the slave might contain other data
          (ie: general_log is enabled on the slave). The statement will
          be marked as unsafe for SBR in decide_logging_format().
4151 4152 4153 4154 4155
  @remark Note that even in prelocked mode it is important to correctly
          determine lock type value. In this mode lock type is passed to
          handler::start_stmt() method and can be used by storage engine,
          for example, to determine what kind of row locks it should acquire
          when reading data from the table.
4156 4157
*/

4158 4159 4160
thr_lock_type read_lock_type_for_table(THD *thd,
                                       Query_tables_list *prelocking_ctx,
                                       TABLE_LIST *table_list)
4161
{
4162 4163 4164 4165 4166
  /*
    In cases when this function is called for a sub-statement executed in
    prelocked mode we can't rely on OPTION_BIN_LOG flag in THD::options
    bitmap to determine that binary logging is turned on as this bit can
    be cleared before executing sub-statement. So instead we have to look
4167
    at THD::variables::sql_log_bin member.
4168
  */
4169
  bool log_on= mysql_bin_log.is_open() && thd->variables.sql_log_bin;
4170 4171
  ulong binlog_format= thd->variables.binlog_format;
  if ((log_on == FALSE) || (binlog_format == BINLOG_FORMAT_ROW) ||
4172 4173 4174
      (table_list->table->s->table_category == TABLE_CATEGORY_LOG) ||
      (table_list->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) ||
      !(is_update_query(prelocking_ctx->sql_command) ||
4175 4176
        table_list->prelocking_placeholder ||
        (thd->locked_tables_mode > LTM_LOCK_TABLES)))
4177 4178 4179 4180 4181 4182
    return TL_READ;
  else
    return TL_READ_NO_INSERT;
}


unknown's avatar
unknown committed
4183
/*
4184 4185 4186
  Handle element of prelocking set other than table. E.g. cache routine
  and, if prelocking strategy prescribes so, extend the prelocking set
  with tables and routines used by it.
Konstantin Osipov's avatar
Konstantin Osipov committed
4187 4188 4189

  @param[in]  thd                  Thread context.
  @param[in]  prelocking_ctx       Prelocking context.
4190
  @param[in]  rt                   Element of prelocking set to be processed.
Konstantin Osipov's avatar
Konstantin Osipov committed
4191 4192 4193
  @param[in]  prelocking_strategy  Strategy which specifies how the
                                   prelocking set should be extended when
                                   one of its elements is processed.
Konstantin Osipov's avatar
Konstantin Osipov committed
4194 4195 4196 4197 4198
  @param[in]  has_prelocking_list  Indicates that prelocking set/list for
                                   this statement has already been built.
  @param[in]  ot_ctx               Context of open_table used to recover from
                                   locking failures.
  @param[out] need_prelocking      Set to TRUE if it was detected that this
Konstantin Osipov's avatar
Konstantin Osipov committed
4199 4200 4201 4202 4203 4204 4205 4206
                                   statement will require prelocked mode for
                                   its execution, not touched otherwise.

  @retval FALSE  Success.
  @retval TRUE   Failure (Conflicting metadata lock, OOM, other errors).
*/

static bool
4207 4208 4209
open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
                         Sroutine_hash_entry *rt,
                         Prelocking_strategy *prelocking_strategy,
Konstantin Osipov's avatar
Konstantin Osipov committed
4210 4211
                         bool has_prelocking_list,
                         Open_table_context *ot_ctx,
4212
                         bool *need_prelocking)
Konstantin Osipov's avatar
Konstantin Osipov committed
4213
{
Konstantin Osipov's avatar
Konstantin Osipov committed
4214
  MDL_key::enum_mdl_namespace mdl_type= rt->mdl_request.key.mdl_namespace();
4215
  DBUG_ENTER("open_and_process_routine");
Konstantin Osipov's avatar
Konstantin Osipov committed
4216

Konstantin Osipov's avatar
Konstantin Osipov committed
4217
  switch (mdl_type)
4218
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
4219 4220
  case MDL_key::FUNCTION:
  case MDL_key::PROCEDURE:
Konstantin Osipov's avatar
Konstantin Osipov committed
4221
    {
4222
      sp_head *sp;
Konstantin Osipov's avatar
Konstantin Osipov committed
4223 4224 4225 4226 4227 4228 4229 4230 4231 4232
      /*
        Try to get MDL lock on the routine.
        Note that we do not take locks on top-level CALLs as this can
        lead to a deadlock. Not locking top-level CALLs does not break
        the binlog as only the statements in the called procedure show
        up there, not the CALL itself.
      */
      if (rt != (Sroutine_hash_entry*)prelocking_ctx->sroutines_list.first ||
          mdl_type != MDL_key::PROCEDURE)
      {
4233 4234 4235 4236 4237 4238
        /*
          Since we acquire only shared lock on routines we don't
          need to care about global intention exclusive locks.
        */
        DBUG_ASSERT(rt->mdl_request.type == MDL_SHARED);

4239 4240 4241 4242 4243 4244 4245 4246 4247 4248
        /*
          Waiting for a conflicting metadata lock to go away may
          lead to a deadlock, detected by MDL subsystem.
          If possible, we try to resolve such deadlocks by releasing all
          metadata locks and restarting the pre-locking process.
          To prevent the error from polluting the diagnostics area
          in case of successful resolution, install a special error
          handler for ER_LOCK_DEADLOCK error.
        */
        MDL_deadlock_handler mdl_deadlock_handler(ot_ctx);
Konstantin Osipov's avatar
Konstantin Osipov committed
4249

4250 4251 4252 4253 4254 4255
        thd->push_internal_handler(&mdl_deadlock_handler);
        bool result= thd->mdl_context.acquire_lock(&rt->mdl_request,
                                                   ot_ctx->get_timeout());
        thd->pop_internal_handler();

        if (result)
Konstantin Osipov's avatar
Konstantin Osipov committed
4256
          DBUG_RETURN(TRUE);
4257

Konstantin Osipov's avatar
Konstantin Osipov committed
4258 4259 4260 4261 4262
        DEBUG_SYNC(thd, "after_shared_lock_pname");

        /* Ensures the routine is up-to-date and cached, if exists. */
        if (sp_cache_routine(thd, rt, has_prelocking_list, &sp))
          DBUG_RETURN(TRUE);
Konstantin Osipov's avatar
Konstantin Osipov committed
4263

Konstantin Osipov's avatar
Konstantin Osipov committed
4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275
        /* Remember the version of the routine in the parse tree. */
        if (check_and_update_routine_version(thd, rt, sp))
          DBUG_RETURN(TRUE);

        /* 'sp' is NULL when there is no such routine. */
        if (sp && !has_prelocking_list)
        {
          prelocking_strategy->handle_routine(thd, prelocking_ctx, rt, sp,
                                              need_prelocking);
        }
      }
      else
4276
      {
Konstantin Osipov's avatar
Konstantin Osipov committed
4277 4278 4279 4280 4281 4282
        /*
          If it's a top level call, just make sure we have a recent
          version of the routine, if it exists.
          Validating routine version is unnecessary, since CALL
          does not affect the prepared statement prelocked list.
        */
4283 4284
        if (sp_cache_routine(thd, rt, FALSE, &sp))
          DBUG_RETURN(TRUE);
Konstantin Osipov's avatar
Konstantin Osipov committed
4285 4286
      }
    }
4287
    break;
Konstantin Osipov's avatar
Konstantin Osipov committed
4288
  case MDL_key::TRIGGER:
Konstantin Osipov's avatar
Konstantin Osipov committed
4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318
    /**
      We add trigger entries to lex->sroutines_list, but we don't
      load them here. The trigger entry is only used when building
      a transitive closure of objects used in a statement, to avoid
      adding to this closure objects that are used in the trigger more
      than once.
      E.g. if a trigger trg refers to table t2, and the trigger table t1
      is used multiple times in the statement (say, because it's used in
      function f1() twice), we will only add t2 once to the list of
      tables to prelock.

      We don't take metadata locks on triggers either: they are protected
      by a respective lock on the table, on which the trigger is defined.

      The only two cases which give "trouble" are SHOW CREATE TRIGGER
      and DROP TRIGGER statements. For these, statement syntax doesn't
      specify the table on which this trigger is defined, so we have
      to make a "dirty" read in the data dictionary to find out the
      table name. Once we discover the table name, we take a metadata
      lock on it, and this protects all trigger operations.
      Of course the table, in theory, may disappear between the dirty
      read and metadata lock acquisition, but in that case we just return
      a run-time error.

      Grammar of other trigger DDL statements (CREATE, DROP) requires
      the table to be specified explicitly, so we use the table metadata
      lock to protect trigger metadata in these statements. Similarly, in
      DML we always use triggers together with their tables, and thus don't
      need to take separate metadata locks on them.
    */
4319 4320 4321 4322
    break;
  default:
    /* Impossible type value. */
    DBUG_ASSERT(0);
Konstantin Osipov's avatar
Konstantin Osipov committed
4323 4324 4325 4326 4327
  }
  DBUG_RETURN(FALSE);
}


4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364
/**
  Handle table list element by obtaining metadata lock, opening table or view
  and, if prelocking strategy prescribes so, extending the prelocking set with
  tables and routines used by it.

  @param[in]     thd                  Thread context.
  @param[in]     lex                  LEX structure for statement.
  @param[in]     tables               Table list element to be processed.
  @param[in,out] counter              Number of tables which are open.
  @param[in]     flags                Bitmap of flags to modify how the tables
                                      will be open, see open_table() description
                                      for details.
  @param[in]     prelocking_strategy  Strategy which specifies how the
                                      prelocking set should be extended
                                      when table or view is processed.
  @param[in]     has_prelocking_list  Indicates that prelocking set/list for
                                      this statement has already been built.
  @param[in]     ot_ctx               Context used to recover from a failed
                                      open_table() attempt.
  @param[in]     new_frm_mem          Temporary MEM_ROOT to be used for
                                      parsing .FRMs for views.

  @retval  FALSE  Success.
  @retval  TRUE   Error, reported unless there is a chance to recover from it.
*/

static bool
open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
                       uint *counter, uint flags,
                       Prelocking_strategy *prelocking_strategy,
                       bool has_prelocking_list,
                       Open_table_context *ot_ctx,
                       MEM_ROOT *new_frm_mem)
{
  bool error= FALSE;
  bool safe_to_ignore_table= FALSE;
  DBUG_ENTER("open_and_process_table");
4365
  DEBUG_SYNC(thd, "open_and_process_table");
4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401

  /*
    Ignore placeholders for derived tables. After derived tables
    processing, link to created temporary table will be put here.
    If this is derived table for view then we still want to process
    routines used by this view.
  */
  if (tables->derived)
  {
    if (!tables->view)
      goto end;
    /*
      We restore view's name and database wiped out by derived tables
      processing and fall back to standard open process in order to
      obtain proper metadata locks and do other necessary steps like
      stored routine processing.
    */
    tables->db= tables->view_db.str;
    tables->db_length= tables->view_db.length;
    tables->table_name= tables->view_name.str;
    tables->table_name_length= tables->view_name.length;
  }
  /*
    If this TABLE_LIST object is a placeholder for an information_schema
    table, create a temporary table to represent the information_schema
    table in the query. Do not fill it yet - will be filled during
    execution.
  */
  if (tables->schema_table)
  {
    /*
      If this information_schema table is merged into a mergeable
      view, ignore it for now -- it will be filled when its respective
      TABLE_LIST is processed. This code works only during re-execution.
    */
    if (tables->view)
4402
    {
4403
      MDL_ticket *mdl_ticket;
4404 4405 4406 4407
      /*
        We still need to take a MDL lock on the merged view to protect
        it from concurrent changes.
      */
4408 4409 4410
      if (!open_table_get_mdl_lock(thd, ot_ctx, &tables->mdl_request,
                                   flags, &mdl_ticket) &&
          mdl_ticket != NULL)
4411 4412 4413 4414 4415
        goto process_view_routines;
      /* Fall-through to return error. */
    }
    else if (!mysql_schema_table(thd, lex, tables) &&
             !check_and_update_table_version(thd, tables, tables->table->s))
4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436
    {
      goto end;
    }
    error= TRUE;
    goto end;
  }
  DBUG_PRINT("tcache", ("opening table: '%s'.'%s'  item: %p",
                        tables->db, tables->table_name, tables)); //psergey: invalid read of size 1 here
  (*counter)++;

  /* Not a placeholder: must be a base table or a view. Let us open it. */
  DBUG_ASSERT(!tables->table);

  if (tables->prelocking_placeholder)
  {
    /*
      For the tables added by the pre-locking code, attempt to open
      the table but fail silently if the table does not exist.
      The real failure will occur when/if a statement attempts to use
      that table.
    */
4437 4438
    No_such_table_error_handler no_such_table_handler;
    thd->push_internal_handler(&no_such_table_handler);
4439
    error= open_table(thd, tables, new_frm_mem, ot_ctx);
4440
    thd->pop_internal_handler();
4441
    safe_to_ignore_table= no_such_table_handler.safely_trapped_errors();
4442
  }
4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456
  else if (tables->parent_l && (thd->open_options & HA_OPEN_FOR_REPAIR))
  {
    /*
      Also fail silently for underlying tables of a MERGE table if this
      table is opened for CHECK/REPAIR TABLE statement. This is needed
      to provide complete list of problematic underlying tables in
      CHECK/REPAIR TABLE output.
    */
    Repair_mrg_table_error_handler repair_mrg_table_handler;
    thd->push_internal_handler(&repair_mrg_table_handler);
    error= open_table(thd, tables, new_frm_mem, ot_ctx);
    thd->pop_internal_handler();
    safe_to_ignore_table= repair_mrg_table_handler.safely_trapped_errors();
  }
4457
  else
4458
    error= open_table(thd, tables, new_frm_mem, ot_ctx);
4459 4460 4461 4462 4463

  free_root(new_frm_mem, MYF(MY_KEEP_PREALLOC));

  if (error)
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
4464
    if (! ot_ctx->can_recover_from_failed_open() && safe_to_ignore_table)
4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551
    {
      DBUG_PRINT("info", ("open_table: ignoring table '%s'.'%s'",
                          tables->db, tables->alias));
      error= FALSE;
    }
    goto end;
  }

  /*
    We can't rely on simple check for TABLE_LIST::view to determine
    that this is a view since during re-execution we might reopen
    ordinary table in place of view and thus have TABLE_LIST::view
    set from repvious execution and TABLE_LIST::table set from
    current.
  */
  if (!tables->table && tables->view)
  {
    /* VIEW placeholder */
    (*counter)--;

    /*
      tables->next_global list consists of two parts:
      1) Query tables and underlying tables of views.
      2) Tables used by all stored routines that this statement invokes on
         execution.
      We need to know where the bound between these two parts is. If we've
      just opened a view, which was the last table in part #1, and it
      has added its base tables after itself, adjust the boundary pointer
      accordingly.
    */
    if (lex->query_tables_own_last == &(tables->next_global) &&
        tables->view->query_tables)
      lex->query_tables_own_last= tables->view->query_tables_last;
    /*
      Let us free memory used by 'sroutines' hash here since we never
      call destructor for this LEX.
    */
    my_hash_free(&tables->view->sroutines);
    goto process_view_routines;
  }

  /*
    Special types of open can succeed but still don't set
    TABLE_LIST::table to anything.
  */
  if (tables->open_strategy && !tables->table)
    goto end;

  /*
    If we are not already in prelocked mode and extended table list is not
    yet built we might have to build the prelocking set for this statement.

    Since currently no prelocking strategy prescribes doing anything for
    tables which are only read, we do below checks only if table is going
    to be changed.
  */
  if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
      ! has_prelocking_list &&
      tables->lock_type >= TL_WRITE_ALLOW_WRITE)
  {
    bool need_prelocking= FALSE;
    TABLE_LIST **save_query_tables_last= lex->query_tables_last;
    /*
      Extend statement's table list and the prelocking set with
      tables and routines according to the current prelocking
      strategy.

      For example, for DML statements we need to add tables and routines
      used by triggers which are going to be invoked for this element of
      table list and also add tables required for handling of foreign keys.
    */
    error= prelocking_strategy->handle_table(thd, lex, tables,
                                             &need_prelocking);

    if (need_prelocking && ! lex->requires_prelocking())
      lex->mark_as_requiring_prelocking(save_query_tables_last);

    if (error)
      goto end;
  }

  if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables_mode)
  {
    if (tables->lock_type == TL_WRITE_DEFAULT)
      tables->table->reginfo.lock_type= thd->update_lock_default;
    else if (tables->lock_type == TL_READ_DEFAULT)
      tables->table->reginfo.lock_type=
4552
        read_lock_type_for_table(thd, lex, tables);
4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602
    else
      tables->table->reginfo.lock_type= tables->lock_type;
  }
  tables->table->grant= tables->grant;

  /* Check and update metadata version of a base table. */
  error= check_and_update_table_version(thd, tables, tables->table->s);

  if (error)
    goto end;
  /*
    After opening a MERGE table add the children to the query list of
    tables, so that they are opened too.
    Note that placeholders don't have the handler open.
  */
  /* MERGE tables need to access parent and child TABLE_LISTs. */
  DBUG_ASSERT(tables->table->pos_in_table_list == tables);
  /* Non-MERGE tables ignore this call. */
  if (tables->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST))
  {
    error= TRUE;
    goto end;
  }

process_view_routines:
  /*
    Again we may need cache all routines used by this view and add
    tables used by them to table list.
  */
  if (tables->view &&
      thd->locked_tables_mode <= LTM_LOCK_TABLES &&
      ! has_prelocking_list)
  {
    bool need_prelocking= FALSE;
    TABLE_LIST **save_query_tables_last= lex->query_tables_last;

    error= prelocking_strategy->handle_view(thd, lex, tables,
                                            &need_prelocking);

    if (need_prelocking && ! lex->requires_prelocking())
      lex->mark_as_requiring_prelocking(save_query_tables_last);

    if (error)
      goto end;
  }

end:
  DBUG_RETURN(error);
}

4603 4604 4605 4606 4607 4608 4609
extern "C" uchar *schema_set_get_key(const uchar *record, size_t *length,
                                     my_bool not_used __attribute__((unused)))
{
  TABLE_LIST *table=(TABLE_LIST*) record;
  *length= table->db_length;
  return (uchar*) table->db;
}
4610

4611
/**
4612 4613
  Acquire upgradable (SNW, SNRW) metadata locks on tables used by
  LOCK TABLES or by a DDL statement. Under LOCK TABLES, we can't take
4614
  new locks, so use open_tables_check_upgradable_mdl() instead.
4615

4616 4617 4618 4619 4620 4621 4622
  @param thd               Thread context.
  @param tables_start      Start of list of tables on which upgradable locks
                           should be acquired.
  @param tables_end        End of list of tables.
  @param lock_wait_timeout Seconds to wait before timeout.
  @param flags             Bitmap of flags to modify how the tables will be
                           open, see open_table() description for details.
4623 4624 4625 4626 4627

  @retval FALSE  Success.
  @retval TRUE   Failure (e.g. connection was killed)
*/

4628 4629 4630 4631
bool
lock_table_names(THD *thd,
                 TABLE_LIST *tables_start, TABLE_LIST *tables_end,
                 ulong lock_wait_timeout, uint flags)
4632 4633 4634
{
  MDL_request_list mdl_requests;
  TABLE_LIST *table;
4635 4636
  MDL_request global_request;
  Hash_set<TABLE_LIST, schema_set_get_key> schema_set;
4637

4638 4639
  DBUG_ASSERT(!thd->locked_tables_mode);

4640 4641 4642
  for (table= tables_start; table && table != tables_end;
       table= table->next_global)
  {
4643
    if (table->mdl_request.type >= MDL_SHARED_NO_WRITE &&
4644
        !(table->open_type == OT_TEMPORARY_ONLY ||
4645
          (flags & MYSQL_OPEN_TEMPORARY_ONLY) ||
4646
          (table->open_type != OT_BASE_ONLY &&
4647
           ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) &&
4648
           find_temporary_table(thd, table))))
4649
    {
4650 4651
      if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) &&
          schema_set.insert(table))
4652
        return TRUE;
4653
      mdl_requests.push_front(&table->mdl_request);
4654
    }
4655 4656
  }

4657 4658
  if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) &&
      ! mdl_requests.is_empty())
4659
  {
4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670
    /*
      Scoped locks: Take intention exclusive locks on all involved
      schemas.
    */
    Hash_set<TABLE_LIST, schema_set_get_key>::Iterator it(schema_set);
    while ((table= it++))
    {
      MDL_request *schema_request= new (thd->mem_root) MDL_request;
      if (schema_request == NULL)
        return TRUE;
      schema_request->init(MDL_key::SCHEMA, table->db, "",
4671 4672
                           MDL_INTENTION_EXCLUSIVE,
                           MDL_TRANSACTION);
4673 4674
      mdl_requests.push_front(schema_request);
    }
4675 4676 4677 4678 4679 4680 4681 4682 4683 4684

    /*
      Protect this statement against concurrent global read lock
      by acquiring global intention exclusive lock with statement
      duration.
    */
    if (thd->global_read_lock.can_acquire_protection())
      return TRUE;
    global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
                        MDL_STATEMENT);
4685
    mdl_requests.push_front(&global_request);
4686 4687
  }

4688
  if (thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout))
4689 4690 4691 4692 4693 4694
    return TRUE;

  return FALSE;
}


4695 4696 4697 4698 4699 4700 4701 4702 4703
/**
  Check for upgradable (SNW, SNRW) metadata locks on tables to be opened
  for a DDL statement. Under LOCK TABLES, we can't take new locks, so we
  must check if appropriate locks were pre-acquired.

  @param thd           Thread context.
  @param tables_start  Start of list of tables on which upgradable locks
                       should be searched for.
  @param tables_end    End of list of tables.
4704 4705
  @param flags         Bitmap of flags to modify how the tables will be
                       open, see open_table() description for details.
4706 4707 4708 4709 4710 4711 4712

  @retval FALSE  Success.
  @retval TRUE   Failure (e.g. connection was killed)
*/

static bool
open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
4713
                                 TABLE_LIST *tables_end, uint flags)
4714 4715 4716 4717 4718 4719 4720 4721
{
  TABLE_LIST *table;

  DBUG_ASSERT(thd->locked_tables_mode);

  for (table= tables_start; table && table != tables_end;
       table= table->next_global)
  {
4722
    if (table->mdl_request.type >= MDL_SHARED_NO_WRITE &&
4723
        !(table->open_type == OT_TEMPORARY_ONLY ||
4724
          (flags & MYSQL_OPEN_TEMPORARY_ONLY) ||
4725
          (table->open_type != OT_BASE_ONLY &&
4726
           ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) &&
4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737
           find_temporary_table(thd, table))))
    {
      /*
        We don't need to do anything about the found TABLE instance as it
        will be handled later in open_tables(), we only need to check that
        an upgradable lock is already acquired. When we enter LOCK TABLES
        mode, SNRW locks are acquired before all other locks. So if under
        LOCK TABLES we find that there is TABLE instance with upgradeable
        lock, all other instances of TABLE for the same table will have the
        same ticket.

4738 4739 4740 4741 4742 4743 4744 4745
        Note that this works OK even for CREATE TABLE statements which
        request X type of metadata lock. This is because under LOCK TABLES
        such statements don't create the table but only check if it exists
        or, in most complex case, only insert into it.
        Thus SNRW lock should be enough.

        Note that find_table_for_mdl_upgrade() will report an error if
        no suitable ticket is found.
4746
      */
4747
      if (!find_table_for_mdl_upgrade(thd, table->db, table->table_name, false))
4748 4749 4750 4751 4752 4753 4754 4755
        return TRUE;
    }
  }

  return FALSE;
}


Konstantin Osipov's avatar
Konstantin Osipov committed
4756
/**
unknown's avatar
unknown committed
4757 4758
  Open all tables in list

Konstantin Osipov's avatar
Konstantin Osipov committed
4759 4760 4761 4762 4763 4764 4765 4766 4767
  @param[in]     thd      Thread context.
  @param[in,out] start    List of tables to be open (it can be adjusted for
                          statement that uses tables only implicitly, e.g.
                          for "SELECT f1()").
  @param[out]    counter  Number of tables which were open.
  @param[in]     flags    Bitmap of flags to modify how the tables will be
                          open, see open_table() description for details.
  @param[in]     prelocking_strategy  Strategy which specifies how prelocking
                                      algorithm should work for this statement.
unknown's avatar
unknown committed
4768

Konstantin Osipov's avatar
Konstantin Osipov committed
4769 4770 4771 4772 4773 4774
  @note
    Unless we are already in prelocked mode and prelocking strategy prescribes
    so this function will also precache all SP/SFs explicitly or implicitly
    (via views and triggers) used by the query and add tables needed for their
    execution to table list. Statement that uses SFs, invokes triggers or
    requires foreign key checks will be marked as requiring prelocking.
4775 4776 4777 4778 4779 4780
    Prelocked mode will be enabled for such query during lock_tables() call.

    If query for which we are opening tables is already marked as requiring
    prelocking it won't do such precaching and will simply reuse table list
    which is already built.

Konstantin Osipov's avatar
Konstantin Osipov committed
4781 4782
  @retval  FALSE  Success.
  @retval  TRUE   Error, reported.
unknown's avatar
unknown committed
4783 4784
*/

Konstantin Osipov's avatar
Konstantin Osipov committed
4785
bool open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
Konstantin Osipov's avatar
Konstantin Osipov committed
4786
                Prelocking_strategy *prelocking_strategy)
unknown's avatar
unknown committed
4787
{
4788 4789 4790 4791 4792 4793 4794 4795 4796 4797
  /*
    We use pointers to "next_global" member in the last processed TABLE_LIST
    element and to the "next" member in the last processed Sroutine_hash_entry
    element as iterators over, correspondingly, the table list and stored routines
    list which stay valid and allow to continue iteration when new elements are
    added to the tail of the lists.
  */
  TABLE_LIST **table_to_open;
  Sroutine_hash_entry **sroutine_to_open;
  TABLE_LIST *tables;
4798
  Open_table_context ot_ctx(thd, flags);
Konstantin Osipov's avatar
Konstantin Osipov committed
4799
  bool error= FALSE;
unknown's avatar
VIEW  
unknown committed
4800
  MEM_ROOT new_frm_mem;
Konstantin Osipov's avatar
Konstantin Osipov committed
4801
  bool has_prelocking_list;
4802
  DBUG_ENTER("open_tables");
Konstantin Osipov's avatar
Konstantin Osipov committed
4803

4804 4805 4806 4807 4808 4809 4810 4811
  /* Accessing data in XA_IDLE or XA_PREPARED is not allowed. */
  enum xa_states xa_state= thd->transaction.xid_state.xa_state;
  if (*start && (xa_state == XA_IDLE || xa_state == XA_PREPARED))
  {
    my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
    DBUG_RETURN(true);
  }

4812
  /*
4813 4814
    temporary mem_root for new .frm parsing.
    TODO: variables for size
4815
  */
4816
  init_sql_alloc(&new_frm_mem, 8024, 8024);
4817

4818
  thd->current_tablenr= 0;
Konstantin Osipov's avatar
Konstantin Osipov committed
4819
restart:
4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830
  /*
    Close HANDLER tables which are marked for flush or against which there
    are pending exclusive metadata locks. This is needed both in order to
    avoid deadlocks and to have a point during statement execution at
    which such HANDLERs are closed even if they don't create problems for
    the current session (i.e. to avoid having a DDL blocked by HANDLERs
    opened for a long time).
  */
  if (thd->handler_tables_hash.records)
    mysql_ha_flush(thd);

Konstantin Osipov's avatar
Konstantin Osipov committed
4831
  has_prelocking_list= thd->lex->requires_prelocking();
4832 4833 4834 4835
  table_to_open= start;
  sroutine_to_open= (Sroutine_hash_entry**) &thd->lex->sroutines_list.first;
  *counter= 0;
  thd_proc_info(thd, "Opening tables");
4836

4837 4838 4839 4840 4841
  /*
    If we are executing LOCK TABLES statement or a DDL statement
    (in non-LOCK TABLES mode) we might have to acquire upgradable
    semi-exclusive metadata locks (SNW or SNRW) on some of the
    tables to be opened.
4842 4843 4844 4845
    When executing CREATE TABLE .. If NOT EXISTS .. SELECT, the
    table may not yet exist, in which case we acquire an exclusive
    lock.
    We acquire all such locks at once here as doing this in one
4846 4847 4848 4849 4850
    by one fashion may lead to deadlocks or starvation. Later when
    we will be opening corresponding table pre-acquired metadata
    lock will be reused (thanks to the fact that in recursive case
    metadata locks are acquired without waiting).
  */
4851 4852 4853
  if (! (flags & (MYSQL_OPEN_HAS_MDL_LOCK |
                  MYSQL_OPEN_FORCE_SHARED_MDL |
                  MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)))
4854
  {
4855 4856 4857 4858 4859 4860 4861
    if (thd->locked_tables_mode)
    {
      /*
        Under LOCK TABLES, we can't acquire new locks, so we instead
        need to check if appropriate locks were pre-acquired.
      */
      if (open_tables_check_upgradable_mdl(thd, *start,
4862 4863
                                           thd->lex->first_not_own_table(),
                                           flags))
4864 4865 4866 4867 4868
      {
        error= TRUE;
        goto err;
      }
    }
4869
    else
4870
    {
4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883
      TABLE_LIST *table;
      if (lock_table_names(thd, *start, thd->lex->first_not_own_table(),
                           ot_ctx.get_timeout(), flags))
      {
        error= TRUE;
        goto err;
      }
      for (table= *start; table && table != thd->lex->first_not_own_table();
           table= table->next_global)
      {
        if (table->mdl_request.type >= MDL_SHARED_NO_WRITE)
          table->mdl_request.ticket= NULL;
      }
4884 4885 4886
    }
  }

4887
  /*
4888 4889
    Perform steps of prelocking algorithm until there are unprocessed
    elements in prelocking list/set.
4890
  */
4891 4892 4893
  while (*table_to_open  ||
         (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
          *sroutine_to_open))
unknown's avatar
unknown committed
4894
  {
4895
    /*
4896 4897
      For every table in the list of tables to open, try to find or open
      a table.
4898
    */
4899 4900
    for (tables= *table_to_open; tables;
         table_to_open= &tables->next_global, tables= tables->next_global)
4901
    {
4902 4903 4904 4905
      error= open_and_process_table(thd, thd->lex, tables, counter,
                                    flags, prelocking_strategy,
                                    has_prelocking_list, &ot_ctx,
                                    &new_frm_mem);
unknown's avatar
VIEW  
unknown committed
4906

4907
      if (error)
unknown's avatar
unknown committed
4908
      {
Konstantin Osipov's avatar
Konstantin Osipov committed
4909
        if (ot_ctx.can_recover_from_failed_open())
4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925
        {
          /*
            We have met exclusive metadata lock or old version of table.
            Now we have to close all tables and release metadata locks.
            We also have to throw away set of prelocked tables (and thus
            close tables from this set that were open by now) since it
            is possible that one of tables which determined its content
            was changed.

            Instead of implementing complex/non-robust logic mentioned
            above we simply close and then reopen all tables.

            We have to save pointer to table list element for table which we
            have failed to open since closing tables can trigger removal of
            elements from the table list (if MERGE tables are involved),
          */
4926
          close_tables_for_reopen(thd, start, ot_ctx.start_of_statement_svp());
Konstantin Osipov's avatar
Konstantin Osipov committed
4927

4928 4929 4930 4931 4932
          /*
            Here we rely on the fact that 'tables' still points to the valid
            TABLE_LIST element. Altough currently this assumption is valid
            it may change in future.
          */
4933
          if (ot_ctx.recover_from_failed_open(thd))
4934
            goto err;
4935

4936 4937 4938 4939
          error= FALSE;
          goto restart;
        }
        goto err;
4940
      }
4941 4942

      DEBUG_SYNC(thd, "open_tables_after_open_and_process_table");
unknown's avatar
unknown committed
4943
    }
Konstantin Osipov's avatar
Konstantin Osipov committed
4944 4945

    /*
4946 4947 4948
      If we are not already in prelocked mode and extended table list is
      not yet built for our statement we need to cache routines it uses
      and build the prelocking list for it.
Konstantin Osipov's avatar
Konstantin Osipov committed
4949 4950 4951
      If we are not in prelocked mode but have built the extended table
      list, we still need to call open_and_process_routine() to take
      MDL locks on the routines.
Konstantin Osipov's avatar
Konstantin Osipov committed
4952
    */
Konstantin Osipov's avatar
Konstantin Osipov committed
4953
    if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
Konstantin Osipov's avatar
Konstantin Osipov committed
4954
    {
Konstantin Osipov's avatar
Konstantin Osipov committed
4955 4956 4957
      bool need_prelocking= FALSE;
      TABLE_LIST **save_query_tables_last= thd->lex->query_tables_last;
      /*
4958 4959 4960
        Process elements of the prelocking set which are present there
        since parsing stage or were added to it by invocations of
        Prelocking_strategy methods in the above loop over tables.
Konstantin Osipov's avatar
Konstantin Osipov committed
4961

4962 4963 4964
        For example, if element is a routine, cache it and then,
        if prelocking strategy prescribes so, add tables it uses to the
        table list and routines it might invoke to the prelocking set.
Konstantin Osipov's avatar
Konstantin Osipov committed
4965
      */
4966 4967 4968
      for (Sroutine_hash_entry *rt= *sroutine_to_open; rt;
           sroutine_to_open= &rt->next, rt= rt->next)
      {
Konstantin Osipov's avatar
Konstantin Osipov committed
4969 4970
        error= open_and_process_routine(thd, thd->lex, rt, prelocking_strategy,
                                        has_prelocking_list, &ot_ctx,
4971
                                        &need_prelocking);
Konstantin Osipov's avatar
Konstantin Osipov committed
4972

4973 4974
        if (error)
        {
Konstantin Osipov's avatar
Konstantin Osipov committed
4975 4976
          if (ot_ctx.can_recover_from_failed_open())
          {
4977 4978
            close_tables_for_reopen(thd, start,
                                    ot_ctx.start_of_statement_svp());
4979
            if (ot_ctx.recover_from_failed_open(thd))
Konstantin Osipov's avatar
Konstantin Osipov committed
4980 4981 4982 4983 4984
              goto err;

            error= FALSE;
            goto restart;
          }
4985 4986 4987 4988 4989 4990 4991 4992
          /*
            Serious error during reading stored routines from mysql.proc table.
            Something is wrong with the table or its contents, and an error has
            been emitted; we must abort.
          */
          goto err;
        }
      }
Konstantin Osipov's avatar
Konstantin Osipov committed
4993

4994 4995
      if (need_prelocking && ! thd->lex->requires_prelocking())
        thd->lex->mark_as_requiring_prelocking(save_query_tables_last);
Konstantin Osipov's avatar
Konstantin Osipov committed
4996

4997 4998
      if (need_prelocking && ! *start)
        *start= thd->lex->query_tables;
4999
    }
unknown's avatar
unknown committed
5000
  }
5001

Konstantin Osipov's avatar
Konstantin Osipov committed
5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018
  /*
    After successful open of all tables, including MERGE parents and
    children, attach the children to their parents. At end of statement,
    the children are detached. Attaching and detaching are always done,
    even under LOCK TABLES.
  */
  for (tables= *start; tables; tables= tables->next_global)
  {
    TABLE *tbl= tables->table;

    /* Schema tables may not have a TABLE object here. */
    if (tbl && tbl->file->ht->db_type == DB_TYPE_MRG_MYISAM)
    {
      /* MERGE tables need to access parent and child TABLE_LISTs. */
      DBUG_ASSERT(tbl->pos_in_table_list == tables);
      if (tbl->file->extra(HA_EXTRA_ATTACH_CHILDREN))
      {
Konstantin Osipov's avatar
Konstantin Osipov committed
5019
        error= TRUE;
Konstantin Osipov's avatar
Konstantin Osipov committed
5020 5021 5022 5023 5024
        goto err;
      }
    }
  }

Konstantin Osipov's avatar
Konstantin Osipov committed
5025
err:
5026
  thd_proc_info(thd, 0);
5027
  free_root(&new_frm_mem, MYF(0));              // Free pre-alloced block
5028

5029
  if (error && *table_to_open)
5030
  {
5031
    (*table_to_open)->table= NULL;
5032
  }
Konstantin Osipov's avatar
Konstantin Osipov committed
5033 5034
  DBUG_PRINT("open_tables", ("returning: %d", (int) error));
  DBUG_RETURN(error);
unknown's avatar
unknown committed
5035 5036 5037
}


Konstantin Osipov's avatar
Konstantin Osipov committed
5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073
/**
  Defines how prelocking algorithm for DML statements should handle routines:
  - For CALL statements we do unrolling (i.e. open and lock tables for each
    sub-statement individually). So for such statements prelocking is enabled
    only if stored functions are used in parameter list and only for period
    during which we calculate values of parameters. Thus in this strategy we
    ignore procedure which is directly called by such statement and extend
    the prelocking set only with tables/functions used by SF called from the
    parameter list.
  - For any other statement any routine which is directly or indirectly called
    by statement is going to be executed in prelocked mode. So in this case we
    simply add all tables and routines used by it to the prelocking set.

  @param[in]  thd              Thread context.
  @param[in]  prelocking_ctx   Prelocking context of the statement.
  @param[in]  rt               Prelocking set element describing routine.
  @param[in]  sp               Routine body.
  @param[out] need_prelocking  Set to TRUE if method detects that prelocking
                               required, not changed otherwise.

  @retval FALSE  Success.
  @retval TRUE   Failure (OOM).
*/

bool DML_prelocking_strategy::
handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
               Sroutine_hash_entry *rt, sp_head *sp, bool *need_prelocking)
{
  /*
    We assume that for any "CALL proc(...)" statement sroutines_list will
    have 'proc' as first element (it may have several, consider e.g.
    "proc(sp_func(...)))". This property is currently guaranted by the
    parser.
  */

  if (rt != (Sroutine_hash_entry*)prelocking_ctx->sroutines_list.first ||
Konstantin Osipov's avatar
Konstantin Osipov committed
5074
      rt->mdl_request.key.mdl_namespace() != MDL_key::PROCEDURE)
Konstantin Osipov's avatar
Konstantin Osipov committed
5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251
  {
    *need_prelocking= TRUE;
    sp_update_stmt_used_routines(thd, prelocking_ctx, &sp->m_sroutines,
                                 rt->belong_to_view);
    (void)sp->add_used_tables_to_table_list(thd,
                                            &prelocking_ctx->query_tables_last,
                                            rt->belong_to_view);
  }
  sp->propagate_attributes(prelocking_ctx);
  return FALSE;
}


/**
  Defines how prelocking algorithm for DML statements should handle table list
  elements:
  - If table has triggers we should add all tables and routines
    used by them to the prelocking set.

  We do not need to acquire metadata locks on trigger names
  in DML statements, since all DDL statements
  that change trigger metadata always lock their
  subject tables.

  @param[in]  thd              Thread context.
  @param[in]  prelocking_ctx   Prelocking context of the statement.
  @param[in]  table_list       Table list element for table.
  @param[in]  sp               Routine body.
  @param[out] need_prelocking  Set to TRUE if method detects that prelocking
                               required, not changed otherwise.

  @retval FALSE  Success.
  @retval TRUE   Failure (OOM).
*/

bool DML_prelocking_strategy::
handle_table(THD *thd, Query_tables_list *prelocking_ctx,
             TABLE_LIST *table_list, bool *need_prelocking)
{
  /* We rely on a caller to check that table is going to be changed. */
  DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE);

  if (table_list->trg_event_map)
  {
    if (table_list->table->triggers)
    {
      *need_prelocking= TRUE;

      if (table_list->table->triggers->
          add_tables_and_routines_for_triggers(thd, prelocking_ctx, table_list))
        return TRUE;
    }
  }

  return FALSE;
}


/**
  Defines how prelocking algorithm for DML statements should handle view -
  all view routines should be added to the prelocking set.

  @param[in]  thd              Thread context.
  @param[in]  prelocking_ctx   Prelocking context of the statement.
  @param[in]  table_list       Table list element for view.
  @param[in]  sp               Routine body.
  @param[out] need_prelocking  Set to TRUE if method detects that prelocking
                               required, not changed otherwise.

  @retval FALSE  Success.
  @retval TRUE   Failure (OOM).
*/

bool DML_prelocking_strategy::
handle_view(THD *thd, Query_tables_list *prelocking_ctx,
            TABLE_LIST *table_list, bool *need_prelocking)
{
  if (table_list->view->uses_stored_routines())
  {
    *need_prelocking= TRUE;

    sp_update_stmt_used_routines(thd, prelocking_ctx,
                                 &table_list->view->sroutines_list,
                                 table_list->top_table());
  }
  return FALSE;
}


/**
  Defines how prelocking algorithm for LOCK TABLES statement should handle
  table list elements.

  @param[in]  thd              Thread context.
  @param[in]  prelocking_ctx   Prelocking context of the statement.
  @param[in]  table_list       Table list element for table.
  @param[in]  sp               Routine body.
  @param[out] need_prelocking  Set to TRUE if method detects that prelocking
                               required, not changed otherwise.

  @retval FALSE  Success.
  @retval TRUE   Failure (OOM).
*/

bool Lock_tables_prelocking_strategy::
handle_table(THD *thd, Query_tables_list *prelocking_ctx,
             TABLE_LIST *table_list, bool *need_prelocking)
{
  if (DML_prelocking_strategy::handle_table(thd, prelocking_ctx, table_list,
                                            need_prelocking))
    return TRUE;

  /* We rely on a caller to check that table is going to be changed. */
  DBUG_ASSERT(table_list->lock_type >= TL_WRITE_ALLOW_WRITE);

  return FALSE;
}


/**
  Defines how prelocking algorithm for ALTER TABLE statement should handle
  routines - do nothing as this statement is not supposed to call routines.

  We still can end up in this method when someone tries
  to define a foreign key referencing a view, and not just
  a simple view, but one that uses stored routines.
*/

bool Alter_table_prelocking_strategy::
handle_routine(THD *thd, Query_tables_list *prelocking_ctx,
               Sroutine_hash_entry *rt, sp_head *sp, bool *need_prelocking)
{
  return FALSE;
}


/**
  Defines how prelocking algorithm for ALTER TABLE statement should handle
  table list elements.

  Unlike in DML, we do not process triggers here.

  @param[in]  thd              Thread context.
  @param[in]  prelocking_ctx   Prelocking context of the statement.
  @param[in]  table_list       Table list element for table.
  @param[in]  sp               Routine body.
  @param[out] need_prelocking  Set to TRUE if method detects that prelocking
                               required, not changed otherwise.


  @retval FALSE  Success.
  @retval TRUE   Failure (OOM).
*/

bool Alter_table_prelocking_strategy::
handle_table(THD *thd, Query_tables_list *prelocking_ctx,
             TABLE_LIST *table_list, bool *need_prelocking)
{
  return FALSE;
}


/**
  Defines how prelocking algorithm for ALTER TABLE statement
  should handle view - do nothing. We don't need to add view
  routines to the prelocking set in this case as view is not going
  to be materialized.
*/

bool Alter_table_prelocking_strategy::
handle_view(THD *thd, Query_tables_list *prelocking_ctx,
            TABLE_LIST *table_list, bool *need_prelocking)
{
  return FALSE;
}


5252
/**
unknown's avatar
unknown committed
5253 5254
  Check that lock is ok for tables; Call start stmt if ok

5255 5256 5257
  @param thd             Thread handle.
  @param prelocking_ctx  Prelocking context.
  @param table_list      Table list element for table to be checked.
unknown's avatar
unknown committed
5258

5259 5260
  @retval FALSE - Ok.
  @retval TRUE  - Error.
unknown's avatar
unknown committed
5261 5262
*/

5263 5264 5265
static bool check_lock_and_start_stmt(THD *thd,
                                      Query_tables_list *prelocking_ctx,
                                      TABLE_LIST *table_list)
unknown's avatar
unknown committed
5266 5267
{
  int error;
5268
  thr_lock_type lock_type;
unknown's avatar
unknown committed
5269 5270
  DBUG_ENTER("check_lock_and_start_stmt");

5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285
  /*
    TL_WRITE_DEFAULT and TL_READ_DEFAULT are supposed to be parser only
    types of locks so they should be converted to appropriate other types
    to be passed to storage engine. The exact lock type passed to the
    engine is important as, for example, InnoDB uses it to determine
    what kind of row locks should be acquired when executing statement
    in prelocked mode or under LOCK TABLES with @@innodb_table_locks = 0.
  */
  if (table_list->lock_type == TL_WRITE_DEFAULT)
    lock_type= thd->update_lock_default;
  else if (table_list->lock_type == TL_READ_DEFAULT)
    lock_type= read_lock_type_for_table(thd, prelocking_ctx, table_list);
  else
    lock_type= table_list->lock_type;

5286 5287
  if ((int) lock_type > (int) TL_WRITE_ALLOW_WRITE &&
      (int) table_list->table->reginfo.lock_type <= (int) TL_WRITE_ALLOW_WRITE)
unknown's avatar
unknown committed
5288
  {
5289
    my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias);
unknown's avatar
unknown committed
5290 5291
    DBUG_RETURN(1);
  }
5292
  if ((error= table_list->table->file->start_stmt(thd, lock_type)))
unknown's avatar
unknown committed
5293
  {
5294
    table_list->table->file->print_error(error, MYF(0));
unknown's avatar
unknown committed
5295 5296 5297 5298 5299 5300
    DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}


5301 5302 5303 5304 5305 5306
/**
  @brief Open and lock one table

  @param[in]    thd             thread handle
  @param[in]    table_l         table to open is first table in this list
  @param[in]    lock_type       lock to use for table
Konstantin Osipov's avatar
Konstantin Osipov committed
5307 5308
  @param[in]    flags           options to be used while opening and locking
                                table (see open_table(), mysql_lock_tables())
5309 5310
  @param[in]    prelocking_strategy  Strategy which specifies how prelocking
                                     algorithm should work for this statement.
5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330

  @return       table
    @retval     != NULL         OK, opened table returned
    @retval     NULL            Error

  @note
    If ok, the following are also set:
      table_list->lock_type 	lock_type
      table_list->table		table

  @note
    If table_l is a list, not a single table, the list is temporarily
    broken.

  @detail
    This function is meant as a replacement for open_ltable() when
    MERGE tables can be opened. open_ltable() cannot open MERGE tables.

    There may be more differences between open_n_lock_single_table() and
    open_ltable(). One known difference is that open_ltable() does
5331
    neither call thd->decide_logging_format() nor handle some other logging
5332 5333 5334 5335
    and locking issues because it does not call lock_tables().
*/

TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
5336 5337
                                thr_lock_type lock_type, uint flags,
                                Prelocking_strategy *prelocking_strategy)
5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352
{
  TABLE_LIST *save_next_global;
  DBUG_ENTER("open_n_lock_single_table");

  /* Remember old 'next' pointer. */
  save_next_global= table_l->next_global;
  /* Break list. */
  table_l->next_global= NULL;

  /* Set requested lock type. */
  table_l->lock_type= lock_type;
  /* Allow to open real tables only. */
  table_l->required_type= FRMTYPE_TABLE;

  /* Open the table. */
5353 5354
  if (open_and_lock_tables(thd, table_l, FALSE, flags,
                           prelocking_strategy))
5355 5356 5357 5358 5359 5360 5361 5362 5363
    table_l->table= NULL; /* Just to be sure. */

  /* Restore list. */
  table_l->next_global= save_next_global;

  DBUG_RETURN(table_l->table);
}


unknown's avatar
unknown committed
5364 5365 5366 5367 5368 5369 5370 5371
/*
  Open and lock one table

  SYNOPSIS
    open_ltable()
    thd			Thread handler
    table_list		Table to open is first table in this list
    lock_type		Lock to use for open
5372
    lock_flags          Flags passed to mysql_lock_table
unknown's avatar
unknown committed
5373

5374
  NOTE
5375
    This function doesn't do anything like SP/SF/views/triggers analysis done 
Staale Smedseng's avatar
Staale Smedseng committed
5376
    in open_table()/lock_tables(). It is intended for opening of only one
5377
    concrete table. And used only in special contexts.
5378

unknown's avatar
unknown committed
5379 5380 5381 5382 5383 5384 5385 5386 5387
  RETURN VALUES
    table		Opened table
    0			Error
  
    If ok, the following are also set:
      table_list->lock_type 	lock_type
      table_list->table		table
*/

5388 5389
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
                   uint lock_flags)
unknown's avatar
unknown committed
5390 5391
{
  TABLE *table;
5392
  Open_table_context ot_ctx(thd, lock_flags);
Konstantin Osipov's avatar
Konstantin Osipov committed
5393
  bool error;
unknown's avatar
unknown committed
5394 5395
  DBUG_ENTER("open_ltable");

Staale Smedseng's avatar
Staale Smedseng committed
5396
  /* should not be used in a prelocked_mode context, see NOTE above */
Konstantin Osipov's avatar
Konstantin Osipov committed
5397
  DBUG_ASSERT(thd->locked_tables_mode < LTM_PRELOCKED);
Staale Smedseng's avatar
Staale Smedseng committed
5398

5399
  thd_proc_info(thd, "Opening table");
5400
  thd->current_tablenr= 0;
5401 5402
  /* open_ltable can be used only for BASIC TABLEs */
  table_list->required_type= FRMTYPE_TABLE;
5403

5404 5405 5406
  /* This function can't properly handle requests for such metadata locks. */
  DBUG_ASSERT(table_list->mdl_request.type < MDL_SHARED_NO_WRITE);

5407
  while ((error= open_table(thd, table_list, thd->mem_root, &ot_ctx)) &&
Konstantin Osipov's avatar
Konstantin Osipov committed
5408
         ot_ctx.can_recover_from_failed_open())
5409 5410
  {
    /*
Konstantin Osipov's avatar
Konstantin Osipov committed
5411
      Even though we have failed to open table we still need to
5412
      call release_transactional_locks() to release metadata locks which
5413 5414
      might have been acquired successfully.
    */
5415
    thd->mdl_context.rollback_to_savepoint(ot_ctx.start_of_statement_svp());
Konstantin Osipov's avatar
Konstantin Osipov committed
5416
    table_list->mdl_request.ticket= 0;
5417
    if (ot_ctx.recover_from_failed_open(thd))
5418 5419
      break;
  }
unknown's avatar
unknown committed
5420

Konstantin Osipov's avatar
Konstantin Osipov committed
5421
  if (!error)
unknown's avatar
unknown committed
5422
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
5423
    /*
5424
      We can't have a view or some special "open_strategy" in this function
Konstantin Osipov's avatar
Konstantin Osipov committed
5425 5426 5427 5428
      so there should be a TABLE instance.
    */
    DBUG_ASSERT(table_list->table);
    table= table_list->table;
Konstantin Osipov's avatar
Konstantin Osipov committed
5429
    if (table->file->ht->db_type == DB_TYPE_MRG_MYISAM)
5430 5431 5432 5433 5434 5435 5436 5437 5438 5439
    {
      /* A MERGE table must not come here. */
      /* purecov: begin tested */
      my_error(ER_WRONG_OBJECT, MYF(0), table->s->db.str,
               table->s->table_name.str, "BASE TABLE");
      table= 0;
      goto end;
      /* purecov: end */
    }

unknown's avatar
unknown committed
5440
    table_list->lock_type= lock_type;
unknown's avatar
unknown committed
5441
    table->grant= table_list->grant;
Konstantin Osipov's avatar
Konstantin Osipov committed
5442
    if (thd->locked_tables_mode)
unknown's avatar
unknown committed
5443
    {
5444
      if (check_lock_and_start_stmt(thd, thd->lex, table_list))
unknown's avatar
unknown committed
5445 5446 5447 5448
	table= 0;
    }
    else
    {
5449
      DBUG_ASSERT(thd->lock == 0);	// You must lock everything at once
unknown's avatar
unknown committed
5450
      if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK)
5451
	if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1,
5452
                                            lock_flags)))
5453
        {
5454
          table= 0;
5455
        }
unknown's avatar
unknown committed
5456 5457
    }
  }
Konstantin Osipov's avatar
Konstantin Osipov committed
5458 5459
  else
    table= 0;
5460

Konstantin Osipov's avatar
Konstantin Osipov committed
5461
end:
5462
  if (table == NULL)
5463
  {
5464 5465
    if (!thd->in_sub_stmt)
      trans_rollback_stmt(thd);
5466
    close_thread_tables(thd);
5467
  }
5468
  thd_proc_info(thd, 0);
unknown's avatar
unknown committed
5469 5470 5471
  DBUG_RETURN(table);
}

unknown's avatar
unknown committed
5472

Konstantin Osipov's avatar
Konstantin Osipov committed
5473
/**
5474
  Open all tables in list, locks them and optionally process derived tables.
unknown's avatar
unknown committed
5475

Konstantin Osipov's avatar
Konstantin Osipov committed
5476 5477 5478 5479 5480 5481 5482 5483
  @param thd		      Thread context.
  @param tables	              List of tables for open and locking.
  @param derived              If to handle derived tables.
  @param flags                Bitmap of options to be used to open and lock
                              tables (see open_tables() and mysql_lock_tables()
                              for details).
  @param prelocking_strategy  Strategy which specifies how prelocking algorithm
                              should work for this statement.
unknown's avatar
unknown committed
5484

Konstantin Osipov's avatar
Konstantin Osipov committed
5485
  @note
5486 5487
    The thr_lock locks will automatically be freed by
    close_thread_tables().
5488

Konstantin Osipov's avatar
Konstantin Osipov committed
5489 5490
  @retval FALSE  OK.
  @retval TRUE   Error
unknown's avatar
unknown committed
5491 5492
*/

5493 5494 5495
bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
                          bool derived, uint flags,
                          Prelocking_strategy *prelocking_strategy)
unknown's avatar
unknown committed
5496 5497
{
  uint counter;
5498
  MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
5499
  DBUG_ENTER("open_and_lock_tables");
5500
  DBUG_PRINT("enter", ("derived handling: %d", derived));
5501

5502
  if (open_tables(thd, &tables, &counter, flags, prelocking_strategy))
5503
    goto err;
5504 5505 5506 5507 5508 5509 5510 5511

  DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", {
                  const char *old_proc_info= thd->proc_info;
                  thd->proc_info= "DBUG sleep";
                  my_sleep(6000000);
                  thd->proc_info= old_proc_info;});

  if (lock_tables(thd, tables, counter, flags))
5512
    goto err;
5513

5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526
  if (derived)
  {
    if (mysql_handle_derived(thd->lex, &mysql_derived_prepare))
      goto err;
    if (thd->fill_derived_tables() &&
        mysql_handle_derived(thd->lex, &mysql_derived_filling))
    {
      mysql_handle_derived(thd->lex, &mysql_derived_cleanup);
      goto err;
    }
    if (!thd->lex->describe)
      mysql_handle_derived(thd->lex, &mysql_derived_cleanup);
  }
5527

Konstantin Osipov's avatar
Konstantin Osipov committed
5528
  DBUG_RETURN(FALSE);
5529 5530 5531 5532 5533 5534 5535
err:
  if (! thd->in_sub_stmt)
    trans_rollback_stmt(thd);  /* Necessary if derived handling failed. */
  close_thread_tables(thd);
  /* Don't keep locks for a failed statement. */
  thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
5536 5537 5538
}


5539 5540 5541 5542 5543 5544
/*
  Open all tables in list and process derived tables

  SYNOPSIS
    open_normal_and_derived_tables
    thd		- thread handler
5545
    tables	- list of tables for open
5546 5547
    flags       - bitmap of flags to modify how the tables will be open:
                  MYSQL_LOCK_IGNORE_FLUSH - open table even if someone has
5548
                  done a flush on it.
5549 5550 5551 5552 5553 5554 5555 5556 5557 5558

  RETURN
    FALSE - ok
    TRUE  - error

  NOTE 
    This is to be used on prepare stage when you don't read any
    data from the tables.
*/

5559
bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags)
5560
{
5561
  DML_prelocking_strategy prelocking_strategy;
5562
  uint counter;
5563
  MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
5564
  DBUG_ENTER("open_normal_and_derived_tables");
unknown's avatar
unknown committed
5565
  DBUG_ASSERT(!thd->fill_derived_tables());
5566
  if (open_tables(thd, &tables, &counter, flags, &prelocking_strategy) ||
unknown's avatar
unknown committed
5567
      mysql_handle_derived(thd->lex, &mysql_derived_prepare))
5568 5569
    goto end;

unknown's avatar
unknown committed
5570
  DBUG_RETURN(0);
5571
end:
5572 5573 5574 5575 5576 5577 5578 5579
  /*
    No need to commit/rollback the statement transaction: it's
    either not started or we're filling in an INFORMATION_SCHEMA
    table on the fly, and thus mustn't manipulate with the
    transaction of the enclosing statement.
  */
  DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
              (thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
5580 5581 5582 5583 5584
  close_thread_tables(thd);
  /* Don't keep locks for a failed statement. */
  thd->mdl_context.rollback_to_savepoint(mdl_savepoint);

  DBUG_RETURN(TRUE); /* purecov: inspected */
5585 5586 5587
}


5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600
/*
  Mark all real tables in the list as free for reuse.

  SYNOPSIS
    mark_real_tables_as_free_for_reuse()
      thd   - thread context
      table - head of the list of tables

  DESCRIPTION
    Marks all real tables in the list (i.e. not views, derived
    or schema tables) as free for reuse.
*/

5601
static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table_list)
5602
{
5603 5604
  TABLE_LIST *table;
  for (table= table_list; table; table= table->next_global)
5605
    if (!table->placeholder())
5606
    {
5607
      table->table->query_id= 0;
5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619
    }
  for (table= table_list; table; table= table->next_global)
    if (!table->placeholder())
    {
      /*
        Detach children of MyISAMMRG tables used in
        sub-statements, they will be reattached at open.
        This has to be done in a separate loop to make sure
        that children have had their query_id cleared.
      */
      table->table->file->extra(HA_EXTRA_DETACH_CHILDREN);
    }
5620 5621 5622
}


5623 5624
/**
  Lock all tables in a list.
unknown's avatar
unknown committed
5625

5626 5627 5628 5629
  @param  thd           Thread handler
  @param  tables        Tables to lock
  @param  count         Number of opened tables
  @param  flags         Options (see mysql_lock_tables() for details)
unknown's avatar
unknown committed
5630

5631 5632
  You can't call lock_tables() while holding thr_lock locks, as
  this would break the dead-lock-free handling thr_lock gives us.
5633
  You must always get all needed locks at once.
5634

5635 5636 5637
  If the query for which we are calling this function is marked as
  requiring prelocking, this function will change
  locked_tables_mode to LTM_PRELOCKED.
5638

5639 5640
  @retval FALSE         Success. 
  @retval TRUE          A lock wait timeout, deadlock or out of memory.
unknown's avatar
unknown committed
5641 5642
*/

Konstantin Osipov's avatar
Konstantin Osipov committed
5643
bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
5644
                 uint flags)
unknown's avatar
unknown committed
5645
{
unknown's avatar
unknown committed
5646
  TABLE_LIST *table;
5647 5648 5649 5650 5651 5652

  DBUG_ENTER("lock_tables");
  /*
    We can't meet statement requiring prelocking if we already
    in prelocked mode.
  */
Konstantin Osipov's avatar
Konstantin Osipov committed
5653 5654
  DBUG_ASSERT(thd->locked_tables_mode <= LTM_LOCK_TABLES ||
              !thd->lex->requires_prelocking());
5655

5656
  if (!tables && !thd->lex->requires_prelocking())
5657
    DBUG_RETURN(thd->decide_logging_format(tables));
unknown's avatar
unknown committed
5658

5659
  /*
Konstantin Osipov's avatar
Konstantin Osipov committed
5660 5661 5662 5663
    Check for thd->locked_tables_mode to avoid a redundant
    and harmful attempt to lock the already locked tables again.
    Checking for thd->lock is not enough in some situations. For example,
    if a stored function contains
5664
    "drop table t3; create temporary t3 ..; insert into t3 ...;"
Konstantin Osipov's avatar
Konstantin Osipov committed
5665 5666 5667
    thd->lock may be 0 after drop tables, whereas locked_tables_mode
    is still on. In this situation an attempt to lock temporary
    table t3 will lead to a memory leak.
5668
  */
Konstantin Osipov's avatar
Konstantin Osipov committed
5669
  if (! thd->locked_tables_mode)
unknown's avatar
unknown committed
5670
  {
5671
    DBUG_ASSERT(thd->lock == 0);	// You must lock everything at once
unknown's avatar
unknown committed
5672
    TABLE **start,**ptr;
5673

5674
    if (!(ptr=start=(TABLE**) thd->alloc(sizeof(TABLE*)*count)))
Konstantin Osipov's avatar
Konstantin Osipov committed
5675
      DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
5676
    for (table= tables; table; table= table->next_global)
unknown's avatar
unknown committed
5677
    {
5678
      if (!table->placeholder())
unknown's avatar
unknown committed
5679 5680
	*(ptr++)= table->table;
    }
5681 5682 5683 5684

    /* We have to emulate LOCK TABLES if we are statement needs prelocking. */
    if (thd->lex->requires_prelocking())
    {
unknown's avatar
unknown committed
5685
      /*
5686 5687 5688 5689
        A query that modifies autoinc column in sub-statement can make the 
        master and slave inconsistent.
        We can solve these problems in mixed mode by switching to binlogging 
        if at least one updated table is used by sub-statement
unknown's avatar
unknown committed
5690
      */
5691
      if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables && 
5692
          has_write_table_with_auto_increment(thd->lex->first_not_own_table()))
5693
        thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS);
5694 5695
    }

5696 5697
    DEBUG_SYNC(thd, "before_lock_tables_takes_lock");

5698
    if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start),
5699
                                        flags)))
Konstantin Osipov's avatar
Konstantin Osipov committed
5700
      DBUG_RETURN(TRUE);
5701

5702 5703
    DEBUG_SYNC(thd, "after_lock_tables_takes_lock");

5704 5705 5706 5707 5708 5709 5710 5711
    if (thd->lex->requires_prelocking() &&
        thd->lex->sql_command != SQLCOM_LOCK_TABLES)
    {
      TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
      /*
        We just have done implicit LOCK TABLES, and now we have
        to emulate first open_and_lock_tables() after it.

5712 5713 5714 5715 5716 5717 5718 5719 5720 5721
        When open_and_lock_tables() is called for a single table out of
        a table list, the 'next_global' chain is temporarily broken. We
        may not find 'first_not_own' before the end of the "list".
        Look for example at those places where open_n_lock_single_table()
        is called. That function implements the temporary breaking of
        a table list for opening a single table.
      */
      for (table= tables;
           table && table != first_not_own;
           table= table->next_global)
5722
      {
5723
        if (!table->placeholder())
5724 5725
        {
          table->table->query_id= thd->query_id;
5726
          if (check_lock_and_start_stmt(thd, thd->lex, table))
5727
          {
Konstantin Osipov's avatar
Konstantin Osipov committed
5728
            mysql_unlock_tables(thd, thd->lock);
Konstantin Osipov's avatar
Konstantin Osipov committed
5729
            thd->lock= 0;
Konstantin Osipov's avatar
Konstantin Osipov committed
5730
            DBUG_RETURN(TRUE);
5731 5732 5733 5734 5735 5736 5737 5738
          }
        }
      }
      /*
        Let us mark all tables which don't belong to the statement itself,
        and was marked as occupied during open_tables() as free for reuse.
      */
      mark_real_tables_as_free_for_reuse(first_not_own);
Konstantin Osipov's avatar
Konstantin Osipov committed
5739
      DBUG_PRINT("info",("locked_tables_mode= LTM_PRELOCKED"));
5740
      thd->enter_locked_tables_mode(LTM_PRELOCKED);
5741
    }
unknown's avatar
unknown committed
5742
  }
unknown's avatar
unknown committed
5743 5744
  else
  {
5745
    TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756
    /*
      When open_and_lock_tables() is called for a single table out of
      a table list, the 'next_global' chain is temporarily broken. We
      may not find 'first_not_own' before the end of the "list".
      Look for example at those places where open_n_lock_single_table()
      is called. That function implements the temporary breaking of
      a table list for opening a single table.
    */
    for (table= tables;
         table && table != first_not_own;
         table= table->next_global)
unknown's avatar
unknown committed
5757
    {
5758 5759 5760 5761 5762 5763 5764
      if (table->placeholder())
        continue;

      /*
        In a stored function or trigger we should ensure that we won't change
        a table that is already used by the calling statement.
      */
Konstantin Osipov's avatar
Konstantin Osipov committed
5765
      if (thd->locked_tables_mode >= LTM_PRELOCKED &&
5766 5767 5768 5769
          table->lock_type >= TL_WRITE_ALLOW_WRITE)
      {
        for (TABLE* opentab= thd->open_tables; opentab; opentab= opentab->next)
        {
Staale Smedseng's avatar
Staale Smedseng committed
5770 5771
          if (table->table->s == opentab->s && opentab->query_id &&
              table->table->query_id != opentab->query_id)
5772 5773
          {
            my_error(ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG, MYF(0),
Staale Smedseng's avatar
Staale Smedseng committed
5774
                     table->table->s->table_name.str);
Konstantin Osipov's avatar
Konstantin Osipov committed
5775
            DBUG_RETURN(TRUE);
5776 5777 5778 5779
          }
        }
      }

5780
      if (check_lock_and_start_stmt(thd, thd->lex, table))
unknown's avatar
unknown committed
5781
      {
Konstantin Osipov's avatar
Konstantin Osipov committed
5782
	DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
5783 5784
      }
    }
5785 5786 5787 5788 5789 5790 5791 5792
    /*
      If we are under explicit LOCK TABLES and our statement requires
      prelocking, we should mark all "additional" tables as free for use
      and enter prelocked mode.
    */
    if (thd->lex->requires_prelocking())
    {
      mark_real_tables_as_free_for_reuse(first_not_own);
Konstantin Osipov's avatar
Konstantin Osipov committed
5793 5794 5795
      DBUG_PRINT("info",
                 ("thd->locked_tables_mode= LTM_PRELOCKED_UNDER_LOCK_TABLES"));
      thd->locked_tables_mode= LTM_PRELOCKED_UNDER_LOCK_TABLES;
5796
    }
unknown's avatar
unknown committed
5797
  }
5798

5799
  DBUG_RETURN(thd->decide_logging_format(tables));
unknown's avatar
unknown committed
5800 5801
}

unknown's avatar
unknown committed
5802

5803
/**
5804 5805 5806
  Prepare statement for reopening of tables and recalculation of set of
  prelocked tables.

5807 5808 5809 5810 5811 5812 5813 5814 5815 5816
  @param[in] thd         Thread context.
  @param[in,out] tables  List of tables which we were trying to open
                         and lock.
  @param[in] start_of_statement_svp MDL savepoint which represents the set
                         of metadata locks which the current transaction
                         managed to acquire before execution of the current
                         statement and to which we should revert before
                         trying to reopen tables. NULL if no metadata locks
                         were held and thus all metadata locks should be
                         released.
5817 5818
*/

5819
void close_tables_for_reopen(THD *thd, TABLE_LIST **tables,
5820
                             const MDL_savepoint &start_of_statement_svp)
5821
{
Konstantin Osipov's avatar
Konstantin Osipov committed
5822 5823 5824
  TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
  TABLE_LIST *tmp;

5825 5826 5827 5828
  /*
    If table list consists only from tables from prelocking set, table list
    for new attempt should be empty, so we have to update list's root pointer.
  */
Konstantin Osipov's avatar
Konstantin Osipov committed
5829
  if (first_not_own_table == *tables)
5830
    *tables= 0;
5831
  thd->lex->chop_off_not_own_tables();
Konstantin Osipov's avatar
Konstantin Osipov committed
5832 5833 5834 5835 5836
  /* Reset MDL tickets for procedures/functions */
  for (Sroutine_hash_entry *rt=
         (Sroutine_hash_entry*)thd->lex->sroutines_list.first;
       rt; rt= rt->next)
    rt->mdl_request.ticket= NULL;
5837
  sp_remove_not_own_routines(thd->lex);
Konstantin Osipov's avatar
Konstantin Osipov committed
5838
  for (tmp= *tables; tmp; tmp= tmp->next_global)
Konstantin Osipov's avatar
Konstantin Osipov committed
5839
  {
5840
    tmp->table= 0;
Konstantin Osipov's avatar
Konstantin Osipov committed
5841
    tmp->mdl_request.ticket= NULL;
Konstantin Osipov's avatar
Konstantin Osipov committed
5842 5843
    /* We have to cleanup translation tables of views. */
    tmp->cleanup_items();
Konstantin Osipov's avatar
Konstantin Osipov committed
5844
  }
5845 5846 5847 5848 5849 5850 5851 5852
  /*
    No need to commit/rollback the statement transaction: it's
    either not started or we're filling in an INFORMATION_SCHEMA
    table on the fly, and thus mustn't manipulate with the
    transaction of the enclosing statement.
  */
  DBUG_ASSERT(thd->transaction.stmt.is_empty() ||
              (thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
Konstantin Osipov's avatar
Konstantin Osipov committed
5853
  close_thread_tables(thd);
5854
  thd->mdl_context.rollback_to_savepoint(start_of_statement_svp);
5855 5856 5857
}


5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876
/**
  Open a single table without table caching and don't add it to
  THD::open_tables. Depending on the 'add_to_temporary_tables_list' value,
  the opened TABLE instance will be addded to THD::temporary_tables list.

  @param thd                          Thread context.
  @param path                         Path (without .frm)
  @param db                           Database name.
  @param table_name                   Table name.
  @param add_to_temporary_tables_list Specifies if the opened TABLE
                                      instance should be linked into
                                      THD::temporary_tables list.

  @note This function is used:
    - by alter_table() to open a temporary table;
    - when creating a temporary table with CREATE TEMPORARY TABLE.

  @return TABLE instance for opened table.
  @retval NULL on error.
unknown's avatar
unknown committed
5877 5878
*/

5879 5880 5881
TABLE *open_table_uncached(THD *thd, const char *path, const char *db,
                           const char *table_name,
                           bool add_to_temporary_tables_list)
unknown's avatar
unknown committed
5882 5883
{
  TABLE *tmp_table;
5884
  TABLE_SHARE *share;
unknown's avatar
unknown committed
5885 5886 5887
  char cache_key[MAX_DBKEY_LENGTH], *saved_cache_key, *tmp_path;
  uint key_length;
  TABLE_LIST table_list;
5888
  DBUG_ENTER("open_table_uncached");
unknown's avatar
unknown committed
5889 5890 5891 5892 5893
  DBUG_PRINT("enter",
             ("table: '%s'.'%s'  path: '%s'  server_id: %u  "
              "pseudo_thread_id: %lu",
              db, table_name, path,
              (uint) thd->server_id, (ulong) thd->variables.pseudo_thread_id));
5894

unknown's avatar
unknown committed
5895 5896 5897 5898 5899 5900 5901 5902
  table_list.db=         (char*) db;
  table_list.table_name= (char*) table_name;
  /* Create the cache_key for temporary tables */
  key_length= create_table_def_key(thd, cache_key, &table_list, 1);

  if (!(tmp_table= (TABLE*) my_malloc(sizeof(*tmp_table) + sizeof(*share) +
                                      strlen(path)+1 + key_length,
                                      MYF(MY_WME))))
unknown's avatar
unknown committed
5903 5904
    DBUG_RETURN(0);				/* purecov: inspected */

unknown's avatar
unknown committed
5905 5906 5907 5908 5909
  share= (TABLE_SHARE*) (tmp_table+1);
  tmp_path= (char*) (share+1);
  saved_cache_key= strmov(tmp_path, path)+1;
  memcpy(saved_cache_key, cache_key, key_length);

5910
  init_tmp_table_share(thd, share, saved_cache_key, key_length,
unknown's avatar
unknown committed
5911 5912 5913 5914 5915 5916 5917 5918
                       strend(saved_cache_key)+1, tmp_path);

  if (open_table_def(thd, share, 0) ||
      open_table_from_share(thd, share, table_name,
                            (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE |
                                    HA_GET_INDEX),
                            READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD,
                            ha_open_options,
unknown's avatar
unknown committed
5919
                            tmp_table, FALSE))
unknown's avatar
unknown committed
5920
  {
unknown's avatar
unknown committed
5921 5922
    /* No need to lock share->mutex as this is not needed for tmp tables */
    free_table_share(share);
5923
    my_free(tmp_table);
unknown's avatar
unknown committed
5924 5925 5926
    DBUG_RETURN(0);
  }

unknown's avatar
unknown committed
5927
  tmp_table->reginfo.lock_type= TL_WRITE;	 // Simulate locked
5928
  share->tmp_table= (tmp_table->file->has_transactions() ? 
5929
                     TRANSACTIONAL_TMP_TABLE : NON_TRANSACTIONAL_TMP_TABLE);
5930

5931
  if (add_to_temporary_tables_list)
unknown's avatar
unknown committed
5932
  {
5933 5934 5935 5936
    /* growing temp list at the head */
    tmp_table->next= thd->temporary_tables;
    if (tmp_table->next)
      tmp_table->next->prev= tmp_table;
unknown's avatar
unknown committed
5937
    thd->temporary_tables= tmp_table;
5938
    thd->temporary_tables->prev= 0;
unknown's avatar
unknown committed
5939 5940
    if (thd->slave_thread)
      slave_open_temp_tables++;
unknown's avatar
unknown committed
5941
  }
unknown's avatar
unknown committed
5942
  tmp_table->pos_in_table_list= 0;
5943 5944
  DBUG_PRINT("tmptable", ("opened table: '%s'.'%s' 0x%lx", tmp_table->s->db.str,
                          tmp_table->s->table_name.str, (long) tmp_table));
unknown's avatar
unknown committed
5945 5946 5947 5948
  DBUG_RETURN(tmp_table);
}


unknown's avatar
unknown committed
5949
bool rm_temporary_table(handlerton *base, char *path)
unknown's avatar
unknown committed
5950 5951
{
  bool error=0;
unknown's avatar
unknown committed
5952 5953
  handler *file;
  char *ext;
5954 5955
  DBUG_ENTER("rm_temporary_table");

unknown's avatar
unknown committed
5956
  strmov(ext= strend(path), reg_ext);
Marc Alff's avatar
Marc Alff committed
5957
  if (mysql_file_delete(key_file_frm, path, MYF(0)))
unknown's avatar
unknown committed
5958
    error=1; /* purecov: inspected */
unknown's avatar
unknown committed
5959 5960
  *ext= 0;				// remove extension
  file= get_new_handler((TABLE_SHARE*) 0, current_thd->mem_root, base);
5961
  if (file && file->ha_delete_table(path))
unknown's avatar
unknown committed
5962
  {
unknown's avatar
unknown committed
5963
    error=1;
unknown's avatar
unknown committed
5964
    sql_print_warning("Could not remove temporary table: '%s', error: %d",
unknown's avatar
unknown committed
5965
                      path, my_errno);
unknown's avatar
unknown committed
5966
  }
unknown's avatar
unknown committed
5967
  delete file;
5968
  DBUG_RETURN(error);
unknown's avatar
unknown committed
5969 5970 5971 5972
}


/*****************************************************************************
unknown's avatar
unknown committed
5973 5974 5975 5976 5977 5978
* The following find_field_in_XXX procedures implement the core of the
* name resolution functionality. The entry point to resolve a column name in a
* list of tables is 'find_field_in_tables'. It calls 'find_field_in_table_ref'
* for each table reference. In turn, depending on the type of table reference,
* 'find_field_in_table_ref' calls one of the 'find_field_in_XXX' procedures
* below specific for the type of table reference.
unknown's avatar
unknown committed
5979 5980
******************************************************************************/

unknown's avatar
unknown committed
5981
/* Special Field pointers as return values of find_field_in_XXX functions. */
unknown's avatar
unknown committed
5982 5983
Field *not_found_field= (Field*) 0x1;
Field *view_ref_found= (Field*) 0x2; 
unknown's avatar
VIEW  
unknown committed
5984

unknown's avatar
unknown committed
5985 5986
#define WRONG_GRANT (Field*) -1

unknown's avatar
unknown committed
5987 5988
static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
{
5989 5990
  DBUG_ENTER("update_field_dependencies");
  if (thd->mark_used_columns != MARK_COLUMNS_NONE)
unknown's avatar
unknown committed
5991
  {
5992
    MY_BITMAP *bitmap;
5993 5994 5995 5996 5997 5998

    /*
      We always want to register the used keys, as the column bitmap may have
      been set for all fields (for example for view).
    */
      
5999
    table->covering_keys.intersect(field->part_of_key);
6000 6001 6002
    table->merge_keys.merge(field->part_of_key);

    if (thd->mark_used_columns == MARK_COLUMNS_READ)
6003
      bitmap= table->read_set;
unknown's avatar
unknown committed
6004
    else
6005
      bitmap= table->write_set;
6006

6007 6008 6009 6010 6011 6012 6013
    /* 
       The test-and-set mechanism in the bitmap is not reliable during
       multi-UPDATE statements under MARK_COLUMNS_READ mode
       (thd->mark_used_columns == MARK_COLUMNS_READ), as this bitmap contains
       only those columns that are used in the SET clause. I.e they are being
       set here. See multi_update::prepare()
    */
6014
    if (bitmap_fast_test_and_set(bitmap, field->field_index))
6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031
    {
      if (thd->mark_used_columns == MARK_COLUMNS_WRITE)
      {
        DBUG_PRINT("warning", ("Found duplicated field"));
        thd->dup_field= field;
      }
      else
      {
        DBUG_PRINT("note", ("Field found before"));
      }
      DBUG_VOID_RETURN;
    }
    if (table->get_fields_in_item_tree)
      field->flags|= GET_FIXED_FIELDS_FLAG;
    table->used_fields++;
  }
  else if (table->get_fields_in_item_tree)
6032
    field->flags|= GET_FIXED_FIELDS_FLAG;
6033
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
6034 6035
}

unknown's avatar
VIEW  
unknown committed
6036 6037

/*
unknown's avatar
unknown committed
6038
  Find a field by name in a view that uses merge algorithm.
unknown's avatar
VIEW  
unknown committed
6039 6040

  SYNOPSIS
unknown's avatar
unknown committed
6041
    find_field_in_view()
unknown's avatar
VIEW  
unknown committed
6042
    thd				thread handler
unknown's avatar
unknown committed
6043
    table_list			view to search for 'name'
unknown's avatar
VIEW  
unknown committed
6044 6045
    name			name of field
    length			length of name
6046
    item_name                   name of item if it will be created (VIEW)
unknown's avatar
unknown committed
6047 6048
    ref				expression substituted in VIEW should be passed
                                using this reference (return view_ref_found)
unknown's avatar
unknown committed
6049
    register_tree_change        TRUE if ref is not stack variable and we
unknown's avatar
unknown committed
6050
                                need register changes in item tree
unknown's avatar
VIEW  
unknown committed
6051 6052 6053 6054

  RETURN
    0			field is not found
    view_ref_found	found value in VIEW (real result is in *ref)
unknown's avatar
unknown committed
6055
    #			pointer to field - only for schema table fields
unknown's avatar
VIEW  
unknown committed
6056 6057
*/

unknown's avatar
unknown committed
6058 6059
static Field *
find_field_in_view(THD *thd, TABLE_LIST *table_list,
6060 6061
                   const char *name, uint length,
                   const char *item_name, Item **ref,
unknown's avatar
unknown committed
6062
                   bool register_tree_change)
unknown's avatar
VIEW  
unknown committed
6063
{
unknown's avatar
unknown committed
6064 6065 6066 6067 6068 6069
  DBUG_ENTER("find_field_in_view");
  DBUG_PRINT("enter",
             ("view: '%s', field name: '%s', item name: '%s', ref 0x%lx",
              table_list->alias, name, item_name, (ulong) ref));
  Field_iterator_view field_it;
  field_it.set(table_list);
unknown's avatar
unknown committed
6070
  Query_arena *arena= 0, backup;  
6071
  
unknown's avatar
unknown committed
6072 6073 6074
  DBUG_ASSERT(table_list->schema_table_reformed ||
              (ref != 0 && table_list->view != 0));
  for (; !field_it.end_of_fields(); field_it.next())
unknown's avatar
VIEW  
unknown committed
6075
  {
unknown's avatar
unknown committed
6076
    if (!my_strcasecmp(system_charset_info, field_it.name(), name))
6077
    {
6078
      // in PS use own arena or data will be freed after prepare
6079 6080
      if (register_tree_change &&
          thd->stmt_arena->is_stmt_prepare_or_first_stmt_execute())
6081
        arena= thd->activate_stmt_arena_if_needed(&backup);
6082 6083 6084 6085
      /*
        create_item() may, or may not create a new Item, depending on
        the column reference. See create_view_field() for details.
      */
unknown's avatar
unknown committed
6086
      Item *item= field_it.create_item(thd);
unknown's avatar
unknown committed
6087
      if (arena)
6088 6089
        thd->restore_active_arena(arena, &backup);
      
unknown's avatar
unknown committed
6090 6091 6092 6093 6094 6095
      if (!item)
        DBUG_RETURN(0);
      /*
       *ref != NULL means that *ref contains the item that we need to
       replace. If the item was aliased by the user, set the alias to
       the replacing item.
6096
       We need to set alias on both ref itself and on ref real item.
unknown's avatar
unknown committed
6097 6098
      */
      if (*ref && !(*ref)->is_autogenerated_name)
6099
      {
unknown's avatar
unknown committed
6100 6101
        item->set_name((*ref)->name, (*ref)->name_length,
                       system_charset_info);
6102 6103 6104
        item->real_item()->set_name((*ref)->name, (*ref)->name_length,
                       system_charset_info);
      }
unknown's avatar
unknown committed
6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132
      if (register_tree_change)
        thd->change_item_tree(ref, item);
      else
        *ref= item;
      DBUG_RETURN((Field*) view_ref_found);
    }
  }
  DBUG_RETURN(0);
}


/*
  Find field by name in a NATURAL/USING join table reference.

  SYNOPSIS
    find_field_in_natural_join()
    thd			 [in]  thread handler
    table_ref            [in]  table reference to search
    name		 [in]  name of field
    length		 [in]  length of name
    ref                  [in/out] if 'name' is resolved to a view field, ref is
                               set to point to the found view field
    register_tree_change [in]  TRUE if ref is not stack variable and we
                               need register changes in item tree
    actual_table         [out] the original table reference where the field
                               belongs - differs from 'table_list' only for
                               NATURAL/USING joins

6133 6134 6135 6136 6137 6138
  DESCRIPTION
    Search for a field among the result fields of a NATURAL/USING join.
    Notice that this procedure is called only for non-qualified field
    names. In the case of qualified fields, we search directly the base
    tables of a natural join.

unknown's avatar
unknown committed
6139
  RETURN
6140 6141 6142
    NULL        if the field was not found
    WRONG_GRANT if no access rights to the found field
    #           Pointer to the found Field
unknown's avatar
unknown committed
6143 6144 6145 6146
*/

static Field *
find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
6147
                           uint length, Item **ref, bool register_tree_change,
6148
                           TABLE_LIST **actual_table)
unknown's avatar
unknown committed
6149
{
6150 6151
  List_iterator_fast<Natural_join_column>
    field_it(*(table_ref->join_columns));
6152
  Natural_join_column *nj_col, *curr_nj_col;
6153
  Field *found_field;
6154
  Query_arena *arena, backup;
unknown's avatar
unknown committed
6155
  DBUG_ENTER("find_field_in_natural_join");
6156
  DBUG_PRINT("enter", ("field name: '%s', ref 0x%lx",
unknown's avatar
unknown committed
6157 6158
		       name, (ulong) ref));
  DBUG_ASSERT(table_ref->is_natural_join && table_ref->join_columns);
6159
  DBUG_ASSERT(*actual_table == NULL);
unknown's avatar
unknown committed
6160

6161
  LINT_INIT(arena);
6162
  LINT_INIT(found_field);
unknown's avatar
unknown committed
6163

6164 6165
  for (nj_col= NULL, curr_nj_col= field_it++; curr_nj_col; 
       curr_nj_col= field_it++)
unknown's avatar
unknown committed
6166
  {
6167 6168 6169 6170 6171 6172 6173 6174 6175
    if (!my_strcasecmp(system_charset_info, curr_nj_col->name(), name))
    {
      if (nj_col)
      {
        my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where);
        DBUG_RETURN(NULL);
      }
      nj_col= curr_nj_col;
    }
unknown's avatar
VIEW  
unknown committed
6176
  }
6177 6178
  if (!nj_col)
    DBUG_RETURN(NULL);
unknown's avatar
unknown committed
6179 6180 6181

  if (nj_col->view_field)
  {
unknown's avatar
unknown committed
6182
    Item *item;
unknown's avatar
unknown committed
6183
    LINT_INIT(arena);
6184 6185
    if (register_tree_change)
      arena= thd->activate_stmt_arena_if_needed(&backup);
6186 6187 6188 6189
    /*
      create_item() may, or may not create a new Item, depending on the
      column reference. See create_view_field() for details.
    */
unknown's avatar
unknown committed
6190
    item= nj_col->create_item(thd);
6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203
    /*
     *ref != NULL means that *ref contains the item that we need to
     replace. If the item was aliased by the user, set the alias to
     the replacing item.
     We need to set alias on both ref itself and on ref real item.
     */
    if (*ref && !(*ref)->is_autogenerated_name)
    {
      item->set_name((*ref)->name, (*ref)->name_length,
                     system_charset_info);
      item->real_item()->set_name((*ref)->name, (*ref)->name_length,
                                  system_charset_info);
    }
6204 6205 6206
    if (register_tree_change && arena)
      thd->restore_active_arena(arena, &backup);

unknown's avatar
unknown committed
6207 6208 6209 6210
    if (!item)
      DBUG_RETURN(NULL);
    DBUG_ASSERT(nj_col->table_field == NULL);
    if (nj_col->table_ref->schema_table_reformed)
6211
    {
unknown's avatar
unknown committed
6212 6213 6214 6215 6216 6217
      /*
        Translation table items are always Item_fields and fixed
        already('mysql_schema_table' function). So we can return
        ->field. It is used only for 'show & where' commands.
      */
      DBUG_RETURN(((Item_field*) (nj_col->view_field->item))->field);
6218
    }
unknown's avatar
unknown committed
6219 6220 6221 6222 6223 6224 6225 6226 6227 6228
    if (register_tree_change)
      thd->change_item_tree(ref, item);
    else
      *ref= item;
    found_field= (Field*) view_ref_found;
  }
  else
  {
    /* This is a base table. */
    DBUG_ASSERT(nj_col->view_field == NULL);
6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243
    /*
      This fix_fields is not necessary (initially this item is fixed by
      the Item_field constructor; after reopen_tables the Item_func_eq
      calls fix_fields on that item), it's just a check during table
      reopening for columns that was dropped by the concurrent connection.
    */
    if (!nj_col->table_field->fixed &&
        nj_col->table_field->fix_fields(thd, (Item **)&nj_col->table_field))
    {
      DBUG_PRINT("info", ("column '%s' was dropped by the concurrent connection",
                          nj_col->table_field->name));
      DBUG_RETURN(NULL);
    }
    DBUG_ASSERT(nj_col->table_ref->table == nj_col->table_field->field->table);
    found_field= nj_col->table_field->field;
unknown's avatar
unknown committed
6244 6245 6246 6247 6248 6249
    update_field_dependencies(thd, found_field, nj_col->table_ref->table);
  }

  *actual_table= nj_col->table_ref;
  
  DBUG_RETURN(found_field);
unknown's avatar
VIEW  
unknown committed
6250 6251
}

6252

unknown's avatar
VIEW  
unknown committed
6253
/*
unknown's avatar
unknown committed
6254
  Find field by name in a base table or a view with temp table algorithm.
unknown's avatar
VIEW  
unknown committed
6255

6256 6257
  The caller is expected to check column-level privileges.

unknown's avatar
VIEW  
unknown committed
6258
  SYNOPSIS
unknown's avatar
unknown committed
6259
    find_field_in_table()
unknown's avatar
VIEW  
unknown committed
6260
    thd				thread handler
unknown's avatar
unknown committed
6261
    table			table where to search for the field
unknown's avatar
VIEW  
unknown committed
6262 6263 6264
    name			name of field
    length			length of name
    allow_rowid			do allow finding of "_rowid" field?
unknown's avatar
unknown committed
6265 6266
    cached_field_index_ptr	cached position in field list (used to speedup
                                lookup for fields in prepared tables)
unknown's avatar
VIEW  
unknown committed
6267 6268

  RETURN
6269 6270
    0	field is not found
    #	pointer to field
unknown's avatar
VIEW  
unknown committed
6271 6272
*/

unknown's avatar
unknown committed
6273 6274
Field *
find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
6275
                    bool allow_rowid, uint *cached_field_index_ptr)
unknown's avatar
unknown committed
6276
{
unknown's avatar
unknown committed
6277 6278
  Field **field_ptr, *field;
  uint cached_field_index= *cached_field_index_ptr;
6279 6280
  DBUG_ENTER("find_field_in_table");
  DBUG_PRINT("enter", ("table: '%s', field name: '%s'", table->alias, name));
unknown's avatar
unknown committed
6281 6282

  /* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */
6283
  if (cached_field_index < table->s->fields &&
6284
      !my_strcasecmp(system_charset_info,
unknown's avatar
unknown committed
6285 6286
                     table->field[cached_field_index]->field_name, name))
    field_ptr= table->field + cached_field_index;
6287
  else if (table->s->name_hash.records)
unknown's avatar
unknown committed
6288
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
6289 6290
    field_ptr= (Field**) my_hash_search(&table->s->name_hash, (uchar*) name,
                                        length);
unknown's avatar
unknown committed
6291 6292 6293 6294 6295 6296 6297 6298 6299
    if (field_ptr)
    {
      /*
        field_ptr points to field in TABLE_SHARE. Convert it to the matching
        field in table
      */
      field_ptr= (table->field + (field_ptr - table->s->field));
    }
  }
unknown's avatar
unknown committed
6300 6301 6302
  else
  {
    if (!(field_ptr= table->field))
unknown's avatar
unknown committed
6303
      DBUG_RETURN((Field *)0);
unknown's avatar
unknown committed
6304 6305 6306 6307 6308 6309
    for (; *field_ptr; ++field_ptr)
      if (!my_strcasecmp(system_charset_info, (*field_ptr)->field_name, name))
        break;
  }

  if (field_ptr && *field_ptr)
unknown's avatar
unknown committed
6310
  {
unknown's avatar
unknown committed
6311 6312
    *cached_field_index_ptr= field_ptr - table->field;
    field= *field_ptr;
unknown's avatar
unknown committed
6313 6314 6315
  }
  else
  {
unknown's avatar
unknown committed
6316 6317
    if (!allow_rowid ||
        my_strcasecmp(system_charset_info, name, "_rowid") ||
unknown's avatar
unknown committed
6318
        table->s->rowid_field_offset == 0)
unknown's avatar
unknown committed
6319
      DBUG_RETURN((Field*) 0);
unknown's avatar
unknown committed
6320
    field= table->field[table->s->rowid_field_offset-1];
unknown's avatar
unknown committed
6321 6322
  }

unknown's avatar
unknown committed
6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336
  update_field_dependencies(thd, field, table);

  DBUG_RETURN(field);
}


/*
  Find field in a table reference.

  SYNOPSIS
    find_field_in_table_ref()
    thd			   [in]  thread handler
    table_list		   [in]  table reference to search
    name		   [in]  name of field
6337
    length		   [in]  field length of name
unknown's avatar
unknown committed
6338 6339
    item_name              [in]  name of item if it will be created (VIEW)
    db_name                [in]  optional database name that qualifies the
6340
    table_name             [in]  optional table name that qualifies the field
unknown's avatar
unknown committed
6341 6342
    ref		       [in/out] if 'name' is resolved to a view field, ref
                                 is set to point to the found view field
6343
    check_privileges       [in]  check privileges
unknown's avatar
unknown committed
6344 6345 6346 6347 6348 6349 6350 6351 6352
    allow_rowid		   [in]  do allow finding of "_rowid" field?
    cached_field_index_ptr [in]  cached position in field list (used to
                                 speedup lookup for fields in prepared tables)
    register_tree_change   [in]  TRUE if ref is not stack variable and we
                                 need register changes in item tree
    actual_table           [out] the original table reference where the field
                                 belongs - differs from 'table_list' only for
                                 NATURAL_USING joins.

unknown's avatar
unknown committed
6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364
  DESCRIPTION
    Find a field in a table reference depending on the type of table
    reference. There are three types of table references with respect
    to the representation of their result columns:
    - an array of Field_translator objects for MERGE views and some
      information_schema tables,
    - an array of Field objects (and possibly a name hash) for stored
      tables,
    - a list of Natural_join_column objects for NATURAL/USING joins.
    This procedure detects the type of the table reference 'table_list'
    and calls the corresponding search routine.

6365 6366
    The routine checks column-level privieleges for the found field.

unknown's avatar
unknown committed
6367 6368 6369 6370 6371 6372 6373 6374
  RETURN
    0			field is not found
    view_ref_found	found value in VIEW (real result is in *ref)
    #			pointer to field
*/

Field *
find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
6375 6376 6377
                        const char *name, uint length,
                        const char *item_name, const char *db_name,
                        const char *table_name, Item **ref,
6378 6379
                        bool check_privileges, bool allow_rowid,
                        uint *cached_field_index_ptr,
unknown's avatar
unknown committed
6380 6381 6382 6383
                        bool register_tree_change, TABLE_LIST **actual_table)
{
  Field *fld;
  DBUG_ENTER("find_field_in_table_ref");
unknown's avatar
unknown committed
6384 6385 6386
  DBUG_ASSERT(table_list->alias);
  DBUG_ASSERT(name);
  DBUG_ASSERT(item_name);
unknown's avatar
unknown committed
6387 6388 6389 6390 6391 6392
  DBUG_PRINT("enter",
             ("table: '%s'  field name: '%s'  item name: '%s'  ref 0x%lx",
              table_list->alias, name, item_name, (ulong) ref));

  /*
    Check that the table and database that qualify the current field name
unknown's avatar
unknown committed
6393 6394
    are the same as the table reference we are going to search for the field.

6395 6396 6397 6398
    Exclude from the test below nested joins because the columns in a
    nested join generally originate from different tables. Nested joins
    also have no table name, except when a nested join is a merge view
    or an information schema table.
unknown's avatar
unknown committed
6399 6400 6401 6402 6403 6404

    We include explicitly table references with a 'field_translation' table,
    because if there are views over natural joins we don't want to search
    inside the view, but we want to search directly in the view columns
    which are represented as a 'field_translation'.

6405 6406
    TODO: Ensure that table_name, db_name and tables->db always points to
          something !
unknown's avatar
unknown committed
6407
  */
6408 6409
  if (/* Exclude nested joins. */
      (!table_list->nested_join ||
unknown's avatar
unknown committed
6410 6411 6412 6413 6414 6415
       /* Include merge views and information schema tables. */
       table_list->field_translation) &&
      /*
        Test if the field qualifiers match the table reference we plan
        to search.
      */
6416 6417
      table_name && table_name[0] &&
      (my_strcasecmp(table_alias_charset, table_list->alias, table_name) ||
unknown's avatar
unknown committed
6418
       (db_name && db_name[0] && table_list->db && table_list->db[0] &&
6419 6420 6421
        (table_list->schema_table ?
         my_strcasecmp(system_charset_info, db_name, table_list->db) :
         strcmp(db_name, table_list->db)))))
unknown's avatar
unknown committed
6422 6423
    DBUG_RETURN(0);

6424
  *actual_table= NULL;
unknown's avatar
unknown committed
6425

unknown's avatar
unknown committed
6426 6427
  if (table_list->field_translation)
  {
unknown's avatar
unknown committed
6428
    /* 'table_list' is a view or an information schema table. */
6429
    if ((fld= find_field_in_view(thd, table_list, name, length, item_name, ref,
6430
                                 register_tree_change)))
unknown's avatar
unknown committed
6431 6432
      *actual_table= table_list;
  }
6433
  else if (!table_list->nested_join)
6434
  {
6435 6436
    /* 'table_list' is a stored table. */
    DBUG_ASSERT(table_list->table);
unknown's avatar
unknown committed
6437
    if ((fld= find_field_in_table(thd, table_list->table, name, length,
6438 6439
                                  allow_rowid,
                                  cached_field_index_ptr)))
unknown's avatar
unknown committed
6440 6441 6442
      *actual_table= table_list;
  }
  else
6443
  {
unknown's avatar
unknown committed
6444
    /*
unknown's avatar
unknown committed
6445 6446 6447 6448 6449
      'table_list' is a NATURAL/USING join, or an operand of such join that
      is a nested join itself.

      If the field name we search for is qualified, then search for the field
      in the table references used by NATURAL/USING the join.
unknown's avatar
unknown committed
6450
    */
6451 6452 6453 6454 6455 6456
    if (table_name && table_name[0])
    {
      List_iterator<TABLE_LIST> it(table_list->nested_join->join_list);
      TABLE_LIST *table;
      while ((table= it++))
      {
6457 6458
        if ((fld= find_field_in_table_ref(thd, table, name, length, item_name,
                                          db_name, table_name, ref,
6459 6460
                                          check_privileges, allow_rowid,
                                          cached_field_index_ptr,
6461 6462 6463 6464 6465 6466 6467
                                          register_tree_change, actual_table)))
          DBUG_RETURN(fld);
      }
      DBUG_RETURN(0);
    }
    /*
      Non-qualified field, search directly in the result columns of the
unknown's avatar
unknown committed
6468 6469 6470
      natural join. The condition of the outer IF is true for the top-most
      natural join, thus if the field is not qualified, we will search
      directly the top-most NATURAL/USING join.
6471 6472
    */
    fld= find_field_in_natural_join(thd, table_list, name, length, ref,
unknown's avatar
unknown committed
6473
                                    register_tree_change, actual_table);
6474
  }
unknown's avatar
unknown committed
6475

6476 6477
  if (fld)
  {
6478
#ifndef NO_EMBEDDED_ACCESS_CHECKS
6479 6480 6481 6482 6483
    /* Check if there are sufficient access rights to the found field. */
    if (check_privileges &&
        check_column_grant_in_table_ref(thd, *actual_table, name, length))
      fld= WRONG_GRANT;
    else
6484
#endif
6485
      if (thd->mark_used_columns != MARK_COLUMNS_NONE)
6486
      {
6487
        /*
6488 6489 6490
          Get rw_set correct for this field so that the handler
          knows that this field is involved in the query and gets
          retrieved/updated
6491
         */
6492 6493 6494 6495 6496 6497
        Field *field_to_set= NULL;
        if (fld == view_ref_found)
        {
          Item *it= (*ref)->real_item();
          if (it->type() == Item::FIELD_ITEM)
            field_to_set= ((Item_field*)it)->field;
6498 6499 6500
          else
          {
            if (thd->mark_used_columns == MARK_COLUMNS_READ)
6501
              it->walk(&Item::register_field_in_read_map, 1, (uchar *) 0);
6502
          }
6503 6504 6505 6506
        }
        else
          field_to_set= fld;
        if (field_to_set)
6507 6508 6509 6510 6511 6512 6513
        {
          TABLE *table= field_to_set->table;
          if (thd->mark_used_columns == MARK_COLUMNS_READ)
            bitmap_set_bit(table->read_set, field_to_set->field_index);
          else
            bitmap_set_bit(table->write_set, field_to_set->field_index);
        }
6514 6515
      }
  }
unknown's avatar
unknown committed
6516
  DBUG_RETURN(fld);
unknown's avatar
unknown committed
6517 6518
}

6519

6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538
/*
  Find field in table, no side effects, only purpose is to check for field
  in table object and get reference to the field if found.

  SYNOPSIS
  find_field_in_table_sef()

  table                         table where to find
  name                          Name of field searched for

  RETURN
    0                   field is not found
    #                   pointer to field
*/

Field *find_field_in_table_sef(TABLE *table, const char *name)
{
  Field **field_ptr;
  if (table->s->name_hash.records)
unknown's avatar
unknown committed
6539
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
6540 6541
    field_ptr= (Field**)my_hash_search(&table->s->name_hash,(uchar*) name,
                                       strlen(name));
unknown's avatar
unknown committed
6542 6543 6544 6545 6546 6547 6548 6549 6550
    if (field_ptr)
    {
      /*
        field_ptr points to field in TABLE_SHARE. Convert it to the matching
        field in table
      */
      field_ptr= (table->field + (field_ptr - table->s->field));
    }
  }
6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565
  else
  {
    if (!(field_ptr= table->field))
      return (Field *)0;
    for (; *field_ptr; ++field_ptr)
      if (!my_strcasecmp(system_charset_info, (*field_ptr)->field_name, name))
        break;
  }
  if (field_ptr)
    return *field_ptr;
  else
    return (Field *)0;
}


6566 6567 6568 6569 6570
/*
  Find field in table list.

  SYNOPSIS
    find_field_in_tables()
unknown's avatar
unknown committed
6571 6572 6573 6574 6575 6576
    thd			  pointer to current thread structure
    item		  field item that should be found
    first_table           list of tables to be searched for item
    last_table            end of the list of tables to search for item. If NULL
                          then search to the end of the list 'first_table'.
    ref			  if 'item' is resolved to a view field, ref is set to
6577
                          point to the found view field
unknown's avatar
unknown committed
6578
    report_error	  Degree of error reporting:
6579 6580
                          - IGNORE_ERRORS then do not report any error
                          - IGNORE_EXCEPT_NON_UNIQUE report only non-unique
unknown's avatar
unknown committed
6581
                            fields, suppress all other errors
6582 6583 6584 6585
                          - REPORT_EXCEPT_NON_UNIQUE report all other errors
                            except when non-unique fields were found
                          - REPORT_ALL_ERRORS
    check_privileges      need to check privileges
unknown's avatar
unknown committed
6586 6587
    register_tree_change  TRUE if ref is not a stack variable and we
                          to need register changes in item tree
6588 6589

  RETURN VALUES
6590 6591 6592
    0			If error: the found field is not unique, or there are
                        no sufficient access priviliges for the found field,
                        or the field is qualified with non-existing table.
6593 6594 6595 6596 6597
    not_found_field	The function was called with report_error ==
                        (IGNORE_ERRORS || IGNORE_EXCEPT_NON_UNIQUE) and a
			field was not found.
    view_ref_found	View field is found, item passed through ref parameter
    found field         If a item was resolved to some field
6598
*/
unknown's avatar
unknown committed
6599 6600

Field *
unknown's avatar
unknown committed
6601 6602
find_field_in_tables(THD *thd, Item_ident *item,
                     TABLE_LIST *first_table, TABLE_LIST *last_table,
6603
		     Item **ref, find_item_error_report_type report_error,
6604
                     bool check_privileges, bool register_tree_change)
unknown's avatar
unknown committed
6605 6606
{
  Field *found=0;
unknown's avatar
unknown committed
6607 6608 6609
  const char *db= item->db_name;
  const char *table_name= item->table_name;
  const char *name= item->field_name;
unknown's avatar
unknown committed
6610
  uint length=(uint) strlen(name);
6611
  char name_buff[NAME_LEN+1];
unknown's avatar
unknown committed
6612 6613
  TABLE_LIST *cur_table= first_table;
  TABLE_LIST *actual_table;
unknown's avatar
unknown committed
6614 6615 6616 6617 6618 6619 6620 6621 6622
  bool allow_rowid;

  if (!table_name || !table_name[0])
  {
    table_name= 0;                              // For easier test
    db= 0;
  }

  allow_rowid= table_name || (cur_table && !cur_table->next_local);
unknown's avatar
unknown committed
6623

unknown's avatar
unknown committed
6624 6625 6626
  if (item->cached_table)
  {
    /*
unknown's avatar
unknown committed
6627 6628
      This shortcut is used by prepared statements. We assume that
      TABLE_LIST *first_table is not changed during query execution (which
6629
      is true for all queries except RENAME but luckily RENAME doesn't
unknown's avatar
unknown committed
6630
      use fields...) so we can rely on reusing pointer to its member.
unknown's avatar
unknown committed
6631
      With this optimization we also miss case when addition of one more
6632
      field makes some prepared query ambiguous and so erroneous, but we
unknown's avatar
unknown committed
6633 6634
      accept this trade off.
    */
unknown's avatar
unknown committed
6635 6636 6637 6638 6639 6640 6641
    TABLE_LIST *table_ref= item->cached_table;
    /*
      The condition (table_ref->view == NULL) ensures that we will call
      find_field_in_table even in the case of information schema tables
      when table_ref->field_translation != NULL.
      */
    if (table_ref->table && !table_ref->view)
6642
    {
unknown's avatar
unknown committed
6643
      found= find_field_in_table(thd, table_ref->table, name, length,
6644
                                 TRUE, &(item->cached_field_index));
6645 6646 6647 6648 6649 6650 6651
#ifndef NO_EMBEDDED_ACCESS_CHECKS
      /* Check if there are sufficient access rights to the found field. */
      if (found && check_privileges &&
          check_column_grant_in_table_ref(thd, table_ref, name, length))
        found= WRONG_GRANT;
#endif
    }
6652
    else
6653
      found= find_field_in_table_ref(thd, table_ref, name, length, item->name,
6654 6655
                                     NULL, NULL, ref, check_privileges,
                                     TRUE, &(item->cached_field_index),
unknown's avatar
unknown committed
6656 6657
                                     register_tree_change,
                                     &actual_table);
unknown's avatar
unknown committed
6658 6659 6660
    if (found)
    {
      if (found == WRONG_GRANT)
6661
	return (Field*) 0;
6662 6663 6664 6665 6666 6667

      /*
        Only views fields should be marked as dependent, not an underlying
        fields.
      */
      if (!table_ref->belong_to_view)
6668 6669
      {
        SELECT_LEX *current_sel= thd->lex->current_select;
unknown's avatar
unknown committed
6670
        SELECT_LEX *last_select= table_ref->select_lex;
unknown's avatar
unknown committed
6671 6672
        /*
          If the field was an outer referencee, mark all selects using this
unknown's avatar
unknown committed
6673
          sub query as dependent on the outer query
unknown's avatar
unknown committed
6674
        */
6675
        if (current_sel != last_select)
unknown's avatar
unknown committed
6676
          mark_select_range_as_dependent(thd, last_select, current_sel,
6677 6678
                                         found, *ref, item);
      }
unknown's avatar
unknown committed
6679 6680 6681 6682
      return found;
    }
  }

6683 6684 6685
  if (db && lower_case_table_names)
  {
    /*
unknown's avatar
unknown committed
6686
      convert database to lower case for comparison.
6687 6688 6689 6690
      We can't do this in Item_field as this would change the
      'name' of the item which may be used in the select list
    */
    strmake(name_buff, db, sizeof(name_buff)-1);
unknown's avatar
unknown committed
6691
    my_casedn_str(files_charset_info, name_buff);
6692 6693
    db= name_buff;
  }
unknown's avatar
unknown committed
6694

6695 6696 6697 6698 6699
  if (last_table)
    last_table= last_table->next_name_resolution_table;

  for (; cur_table != last_table ;
       cur_table= cur_table->next_name_resolution_table)
unknown's avatar
unknown committed
6700
  {
6701 6702
    Field *cur_field= find_field_in_table_ref(thd, cur_table, name, length,
                                              item->name, db, table_name, ref,
6703 6704 6705
                                              (thd->lex->sql_command ==
                                               SQLCOM_SHOW_FIELDS)
                                              ? false : check_privileges,
6706
                                              allow_rowid,
unknown's avatar
unknown committed
6707 6708 6709 6710
                                              &(item->cached_field_index),
                                              register_tree_change,
                                              &actual_table);
    if (cur_field)
6711
    {
unknown's avatar
unknown committed
6712
      if (cur_field == WRONG_GRANT)
6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729
      {
        if (thd->lex->sql_command != SQLCOM_SHOW_FIELDS)
          return (Field*) 0;

        thd->clear_error();
        cur_field= find_field_in_table_ref(thd, cur_table, name, length,
                                           item->name, db, table_name, ref,
                                           false,
                                           allow_rowid,
                                           &(item->cached_field_index),
                                           register_tree_change,
                                           &actual_table);
        if (cur_field)
        {
          Field *nf=new Field_null(NULL,0,Field::NONE,
                                   cur_field->field_name,
                                   &my_charset_bin);
6730
          nf->init(cur_table->table);
6731 6732 6733
          cur_field= nf;
        }
      }
unknown's avatar
unknown committed
6734 6735 6736 6737 6738 6739 6740 6741

      /*
        Store the original table of the field, which may be different from
        cur_table in the case of NATURAL/USING join.
      */
      item->cached_table= (!actual_table->cacheable_table || found) ?
                          0 : actual_table;

6742 6743 6744 6745 6746
      DBUG_ASSERT(thd->where);
      /*
        If we found a fully qualified field we return it directly as it can't
        have duplicates.
       */
unknown's avatar
unknown committed
6747
      if (db)
6748 6749
        return cur_field;

unknown's avatar
unknown committed
6750 6751
      if (found)
      {
6752 6753
        if (report_error == REPORT_ALL_ERRORS ||
            report_error == IGNORE_EXCEPT_NON_UNIQUE)
6754
          my_error(ER_NON_UNIQ_ERROR, MYF(0),
unknown's avatar
unknown committed
6755
                   table_name ? item->full_name() : name, thd->where);
6756
        return (Field*) 0;
unknown's avatar
unknown committed
6757
      }
unknown's avatar
unknown committed
6758
      found= cur_field;
unknown's avatar
unknown committed
6759 6760
    }
  }
6761

unknown's avatar
unknown committed
6762 6763
  if (found)
    return found;
6764 6765 6766 6767 6768 6769 6770 6771

  /*
    If the field was qualified and there were no tables to search, issue
    an error that an unknown table was given. The situation is detected
    as follows: if there were no tables we wouldn't go through the loop
    and cur_table wouldn't be updated by the loop increment part, so it
    will be equal to the first table.
  */
unknown's avatar
unknown committed
6772
  if (table_name && (cur_table == first_table) &&
6773 6774 6775
      (report_error == REPORT_ALL_ERRORS ||
       report_error == REPORT_EXCEPT_NON_UNIQUE))
  {
6776
    char buff[NAME_LEN*2 + 2];
6777 6778 6779 6780 6781 6782 6783
    if (db && db[0])
    {
      strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS);
      table_name=buff;
    }
    my_error(ER_UNKNOWN_TABLE, MYF(0), table_name, thd->where);
  }
6784
  else
unknown's avatar
unknown committed
6785
  {
6786 6787 6788 6789 6790
    if (report_error == REPORT_ALL_ERRORS ||
        report_error == REPORT_EXCEPT_NON_UNIQUE)
      my_error(ER_BAD_FIELD_ERROR, MYF(0), item->full_name(), thd->where);
    else
      found= not_found_field;
unknown's avatar
unknown committed
6791
  }
6792
  return found;
unknown's avatar
unknown committed
6793 6794
}

6795 6796 6797

/*
  Find Item in list of items (find_field_in_tables analog)
6798 6799 6800 6801

  TODO
    is it better return only counter?

6802 6803
  SYNOPSIS
    find_item_in_list()
6804 6805 6806
    find			Item to find
    items			List of items
    counter			To return number of found item
6807
    report_error
6808 6809 6810 6811 6812
      REPORT_ALL_ERRORS		report errors, return 0 if error
      REPORT_EXCEPT_NOT_FOUND	Do not report 'not found' error and
				return not_found_item, report other errors,
				return 0
      IGNORE_ERRORS		Do not report errors, return 0 if error
unknown's avatar
unknown committed
6813 6814 6815 6816 6817 6818 6819
    resolution                  Set to the resolution type if the item is found 
                                (it says whether the item is resolved 
                                 against an alias name,
                                 or as a field name without alias,
                                 or as a field hidden by alias,
                                 or ignoring alias)
                                
6820
  RETURN VALUES
6821 6822 6823 6824 6825
    0			Item is not found or item is not unique,
			error message is reported
    not_found_item	Function was called with
			report_error == REPORT_EXCEPT_NOT_FOUND and
			item was not found. No error message was reported
6826
                        found field
6827 6828
*/

6829
/* Special Item pointer to serve as a return value from find_item_in_list(). */
unknown's avatar
unknown committed
6830
Item **not_found_item= (Item**) 0x1;
6831 6832


unknown's avatar
unknown committed
6833
Item **
6834
find_item_in_list(Item *find, List<Item> &items, uint *counter,
unknown's avatar
unknown committed
6835 6836
                  find_item_error_report_type report_error,
                  enum_resolution_type *resolution)
unknown's avatar
unknown committed
6837 6838
{
  List_iterator<Item> li(items);
6839
  Item **found=0, **found_unaliased= 0, *item;
6840
  const char *db_name=0;
unknown's avatar
unknown committed
6841 6842
  const char *field_name=0;
  const char *table_name=0;
6843
  bool found_unaliased_non_uniq= 0;
6844 6845 6846 6847 6848
  /*
    true if the item that we search for is a valid name reference
    (and not an item that happens to have a name).
  */
  bool is_ref_by_name= 0;
Staale Smedseng's avatar
Staale Smedseng committed
6849
  uint unaliased_counter= 0;
6850

unknown's avatar
unknown committed
6851
  *resolution= NOT_RESOLVED;
6852

6853 6854 6855
  is_ref_by_name= (find->type() == Item::FIELD_ITEM  || 
                   find->type() == Item::REF_ITEM);
  if (is_ref_by_name)
unknown's avatar
unknown committed
6856 6857 6858
  {
    field_name= ((Item_ident*) find)->field_name;
    table_name= ((Item_ident*) find)->table_name;
6859
    db_name=    ((Item_ident*) find)->db_name;
unknown's avatar
unknown committed
6860 6861
  }

6862
  for (uint i= 0; (item=li++); i++)
unknown's avatar
unknown committed
6863
  {
6864
    if (field_name && item->real_item()->type() == Item::FIELD_ITEM)
unknown's avatar
unknown committed
6865
    {
6866
      Item_ident *item_field= (Item_ident*) item;
6867

unknown's avatar
unknown committed
6868 6869 6870 6871 6872 6873
      /*
	In case of group_concat() with ORDER BY condition in the QUERY
	item_field can be field of temporary table without item name 
	(if this field created from expression argument of group_concat()),
	=> we have to check presence of name before compare
      */ 
6874 6875 6876 6877
      if (!item_field->name)
        continue;

      if (table_name)
unknown's avatar
unknown committed
6878
      {
6879 6880 6881
        /*
          If table name is specified we should find field 'field_name' in
          table 'table_name'. According to SQL-standard we should ignore
6882 6883 6884 6885 6886
          aliases in this case.

          Since we should NOT prefer fields from the select list over
          other fields from the tables participating in this select in
          case of ambiguity we have to do extra check outside this function.
6887

6888
          We use strcmp for table names and database names as these may be
6889 6890
          case sensitive. In cases where they are not case sensitive, they
          are always in lower case.
6891 6892

	  item_field->field_name and item_field->table_name can be 0x0 if
6893
	  item is not fix_field()'ed yet.
6894
        */
6895 6896
        if (item_field->field_name && item_field->table_name &&
	    !my_strcasecmp(system_charset_info, item_field->field_name,
6897
                           field_name) &&
unknown's avatar
unknown committed
6898 6899
            !my_strcasecmp(table_alias_charset, item_field->table_name, 
                           table_name) &&
6900 6901 6902
            (!db_name || (item_field->db_name &&
                          !strcmp(item_field->db_name, db_name))))
        {
6903
          if (found_unaliased)
6904
          {
6905 6906 6907 6908 6909 6910 6911
            if ((*found_unaliased)->eq(item, 0))
              continue;
            /*
              Two matching fields in select list.
              We already can bail out because we are searching through
              unaliased names only and will have duplicate error anyway.
            */
6912
            if (report_error != IGNORE_ERRORS)
6913 6914
              my_error(ER_NON_UNIQ_ERROR, MYF(0),
                       find->full_name(), current_thd->where);
6915 6916
            return (Item**) 0;
          }
6917 6918
          found_unaliased= li.ref();
          unaliased_counter= i;
unknown's avatar
unknown committed
6919
          *resolution= RESOLVED_IGNORING_ALIAS;
6920 6921
          if (db_name)
            break;                              // Perfect match
6922 6923
        }
      }
unknown's avatar
unknown committed
6924
      else
6925
      {
unknown's avatar
unknown committed
6926 6927 6928 6929 6930
        int fname_cmp= my_strcasecmp(system_charset_info,
                                     item_field->field_name,
                                     field_name);
        if (!my_strcasecmp(system_charset_info,
                           item_field->name,field_name))
6931
        {
unknown's avatar
unknown committed
6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951
          /*
            If table name was not given we should scan through aliases
            and non-aliased fields first. We are also checking unaliased
            name of the field in then next  else-if, to be able to find
            instantly field (hidden by alias) if no suitable alias or
            non-aliased field was found.
          */
          if (found)
          {
            if ((*found)->eq(item, 0))
              continue;                           // Same field twice
            if (report_error != IGNORE_ERRORS)
              my_error(ER_NON_UNIQ_ERROR, MYF(0),
                       find->full_name(), current_thd->where);
            return (Item**) 0;
          }
          found= li.ref();
          *counter= i;
          *resolution= fname_cmp ? RESOLVED_AGAINST_ALIAS:
	                           RESOLVED_WITH_NO_ALIAS;
6952
        }
unknown's avatar
unknown committed
6953
        else if (!fname_cmp)
6954
        {
unknown's avatar
unknown committed
6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966
          /*
            We will use non-aliased field or react on such ambiguities only if
            we won't be able to find aliased field.
            Again if we have ambiguity with field outside of select list
            we should prefer fields from select list.
          */
          if (found_unaliased)
          {
            if ((*found_unaliased)->eq(item, 0))
              continue;                           // Same field twice
            found_unaliased_non_uniq= 1;
          }
6967 6968 6969
          found_unaliased= li.ref();
          unaliased_counter= i;
        }
unknown's avatar
unknown committed
6970 6971
      }
    }
unknown's avatar
unknown committed
6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988
    else if (!table_name)
    { 
      if (is_ref_by_name && find->name && item->name &&
	  !my_strcasecmp(system_charset_info,item->name,find->name))
      {
        found= li.ref();
        *counter= i;
        *resolution= RESOLVED_AGAINST_ALIAS;
        break;
      }
      else if (find->eq(item,0))
      {
        found= li.ref();
        *counter= i;
        *resolution= RESOLVED_IGNORING_ALIAS;
        break;
      }
6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018
    }
    else if (table_name && item->type() == Item::REF_ITEM &&
             ((Item_ref *)item)->ref_type() == Item_ref::VIEW_REF)
    {
      /*
        TODO:Here we process prefixed view references only. What we should 
        really do is process all types of Item_refs. But this will currently 
        lead to a clash with the way references to outer SELECTs (from the 
        HAVING clause) are handled in e.g. :
        SELECT 1 FROM t1 AS t1_o GROUP BY a
          HAVING (SELECT t1_o.a FROM t1 AS t1_i GROUP BY t1_i.a LIMIT 1).
        Processing all Item_refs here will cause t1_o.a to resolve to itself.
        We still need to process the special case of Item_direct_view_ref 
        because in the context of views they have the same meaning as 
        Item_field for tables.
      */
      Item_ident *item_ref= (Item_ident *) item;
      if (item_ref->name && item_ref->table_name &&
          !my_strcasecmp(system_charset_info, item_ref->name, field_name) &&
          !my_strcasecmp(table_alias_charset, item_ref->table_name,
                         table_name) &&
          (!db_name || (item_ref->db_name && 
                        !strcmp (item_ref->db_name, db_name))))
      {
        found= li.ref();
        *counter= i;
        *resolution= RESOLVED_IGNORING_ALIAS;
        break;
      }
    }
unknown's avatar
unknown committed
7019
  }
7020 7021 7022 7023 7024
  if (!found)
  {
    if (found_unaliased_non_uniq)
    {
      if (report_error != IGNORE_ERRORS)
7025 7026
        my_error(ER_NON_UNIQ_ERROR, MYF(0),
                 find->full_name(), current_thd->where);
7027 7028 7029 7030 7031 7032
      return (Item **) 0;
    }
    if (found_unaliased)
    {
      found= found_unaliased;
      *counter= unaliased_counter;
unknown's avatar
unknown committed
7033
      *resolution= RESOLVED_BEHIND_ALIAS;
7034 7035
    }
  }
7036 7037
  if (found)
    return found;
7038
  if (report_error != REPORT_EXCEPT_NOT_FOUND)
7039 7040
  {
    if (report_error == REPORT_ALL_ERRORS)
7041 7042
      my_error(ER_BAD_FIELD_ERROR, MYF(0),
               find->full_name(), current_thd->where);
7043 7044 7045 7046
    return (Item **) 0;
  }
  else
    return (Item **) not_found_item;
unknown's avatar
unknown committed
7047 7048
}

unknown's avatar
unknown committed
7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076

/*
  Test if a string is a member of a list of strings.

  SYNOPSIS
    test_if_string_in_list()
    find      the string to look for
    str_list  a list of strings to be searched

  DESCRIPTION
    Sequentially search a list of strings for a string, and test whether
    the list contains the same string.

  RETURN
    TRUE  if find is in str_list
    FALSE otherwise
*/

static bool
test_if_string_in_list(const char *find, List<String> *str_list)
{
  List_iterator<String> str_list_it(*str_list);
  String *curr_str;
  size_t find_length= strlen(find);
  while ((curr_str= str_list_it++))
  {
    if (find_length != curr_str->length())
      continue;
7077
    if (!my_strcasecmp(system_charset_info, find, curr_str->ptr()))
unknown's avatar
unknown committed
7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098
      return TRUE;
  }
  return FALSE;
}


/*
  Create a new name resolution context for an item so that it is
  being resolved in a specific table reference.

  SYNOPSIS
    set_new_item_local_context()
    thd        pointer to current thread
    item       item for which new context is created and set
    table_ref  table ref where an item showld be resolved

  DESCRIPTION
    Create a new name resolution context for an item, so that the item
    is resolved only the supplied 'table_ref'.

  RETURN
7099 7100
    FALSE  if all OK
    TRUE   otherwise
unknown's avatar
unknown committed
7101 7102 7103 7104 7105 7106
*/

static bool
set_new_item_local_context(THD *thd, Item_ident *item, TABLE_LIST *table_ref)
{
  Name_resolution_context *context;
7107
  if (!(context= new (thd->mem_root) Name_resolution_context))
unknown's avatar
unknown committed
7108 7109
    return TRUE;
  context->init();
7110 7111
  context->first_name_resolution_table=
    context->last_name_resolution_table= table_ref;
unknown's avatar
unknown committed
7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143
  item->context= context;
  return FALSE;
}


/*
  Find and mark the common columns of two table references.

  SYNOPSIS
    mark_common_columns()
    thd                [in] current thread
    table_ref_1        [in] the first (left) join operand
    table_ref_2        [in] the second (right) join operand
    using_fields       [in] if the join is JOIN...USING - the join columns,
                            if NATURAL join, then NULL
    found_using_fields [out] number of fields from the USING clause that were
                             found among the common fields

  DESCRIPTION
    The procedure finds the common columns of two relations (either
    tables or intermediate join results), and adds an equi-join condition
    to the ON clause of 'table_ref_2' for each pair of matching columns.
    If some of table_ref_XXX represents a base table or view, then we
    create new 'Natural_join_column' instances for each column
    reference and store them in the 'join_columns' of the table
    reference.

  IMPLEMENTATION
    The procedure assumes that store_natural_using_join_columns() was
    called for the previous level of NATURAL/USING joins.

  RETURN
7144 7145
    TRUE   error when some common column is non-unique, or out of memory
    FALSE  OK
unknown's avatar
unknown committed
7146 7147 7148 7149 7150 7151 7152 7153 7154 7155
*/

static bool
mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
                    List<String> *using_fields, uint *found_using_fields)
{
  Field_iterator_table_ref it_1, it_2;
  Natural_join_column *nj_col_1, *nj_col_2;
  Query_arena *arena, backup;
  bool result= TRUE;
unknown's avatar
unknown committed
7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166
  bool first_outer_loop= TRUE;
  /*
    Leaf table references to which new natural join columns are added
    if the leaves are != NULL.
  */
  TABLE_LIST *leaf_1= (table_ref_1->nested_join &&
                       !table_ref_1->is_natural_join) ?
                      NULL : table_ref_1;
  TABLE_LIST *leaf_2= (table_ref_2->nested_join &&
                       !table_ref_2->is_natural_join) ?
                      NULL : table_ref_2;
unknown's avatar
unknown committed
7167 7168

  DBUG_ENTER("mark_common_columns");
7169
  DBUG_PRINT("info", ("operand_1: %s  operand_2: %s",
unknown's avatar
unknown committed
7170 7171
                      table_ref_1->alias, table_ref_2->alias));

7172
  *found_using_fields= 0;
unknown's avatar
unknown committed
7173
  arena= thd->activate_stmt_arena_if_needed(&backup);
unknown's avatar
unknown committed
7174 7175 7176

  for (it_1.set(table_ref_1); !it_1.end_of_fields(); it_1.next())
  {
7177
    bool found= FALSE;
unknown's avatar
unknown committed
7178
    const char *field_name_1;
7179 7180
    /* true if field_name_1 is a member of using_fields */
    bool is_using_column_1;
7181
    if (!(nj_col_1= it_1.get_or_create_column_ref(thd, leaf_1)))
unknown's avatar
unknown committed
7182 7183
      goto err;
    field_name_1= nj_col_1->name();
7184 7185 7186 7187 7188
    is_using_column_1= using_fields && 
      test_if_string_in_list(field_name_1, using_fields);
    DBUG_PRINT ("info", ("field_name_1=%s.%s", 
                         nj_col_1->table_name() ? nj_col_1->table_name() : "", 
                         field_name_1));
unknown's avatar
unknown committed
7189

7190 7191 7192 7193 7194 7195 7196
    /*
      Find a field with the same name in table_ref_2.

      Note that for the second loop, it_2.set() will iterate over
      table_ref_2->join_columns and not generate any new elements or
      lists.
    */
unknown's avatar
unknown committed
7197 7198 7199 7200
    nj_col_2= NULL;
    for (it_2.set(table_ref_2); !it_2.end_of_fields(); it_2.next())
    {
      Natural_join_column *cur_nj_col_2;
7201
      const char *cur_field_name_2;
7202
      if (!(cur_nj_col_2= it_2.get_or_create_column_ref(thd, leaf_2)))
unknown's avatar
unknown committed
7203
        goto err;
7204
      cur_field_name_2= cur_nj_col_2->name();
7205 7206 7207 7208
      DBUG_PRINT ("info", ("cur_field_name_2=%s.%s", 
                           cur_nj_col_2->table_name() ? 
                             cur_nj_col_2->table_name() : "", 
                           cur_field_name_2));
unknown's avatar
unknown committed
7209

unknown's avatar
unknown committed
7210 7211 7212 7213 7214 7215
      /*
        Compare the two columns and check for duplicate common fields.
        A common field is duplicate either if it was already found in
        table_ref_2 (then found == TRUE), or if a field in table_ref_2
        was already matched by some previous field in table_ref_1
        (then cur_nj_col_2->is_common == TRUE).
7216 7217 7218 7219
        Note that it is too early to check the columns outside of the
        USING list for ambiguity because they are not actually "referenced"
        here. These columns must be checked only on unqualified reference 
        by name (e.g. in SELECT list).
unknown's avatar
unknown committed
7220
      */
unknown's avatar
unknown committed
7221 7222
      if (!my_strcasecmp(system_charset_info, field_name_1, cur_field_name_2))
      {
7223 7224 7225
        DBUG_PRINT ("info", ("match c1.is_common=%d", nj_col_1->is_common));
        if (cur_nj_col_2->is_common ||
            (found && (!using_fields || is_using_column_1)))
unknown's avatar
unknown committed
7226 7227 7228 7229 7230 7231 7232 7233
        {
          my_error(ER_NON_UNIQ_ERROR, MYF(0), field_name_1, thd->where);
          goto err;
        }
        nj_col_2= cur_nj_col_2;
        found= TRUE;
      }
    }
unknown's avatar
unknown committed
7234 7235 7236 7237 7238 7239 7240 7241 7242
    if (first_outer_loop && leaf_2)
    {
      /*
        Make sure that the next inner loop "knows" that all columns
        are materialized already.
      */
      leaf_2->is_join_columns_complete= TRUE;
      first_outer_loop= FALSE;
    }
unknown's avatar
unknown committed
7243
    if (!found)
7244
      continue;                                 // No matching field
unknown's avatar
unknown committed
7245 7246 7247 7248 7249 7250

    /*
      field_1 and field_2 have the same names. Check if they are in the USING
      clause (if present), mark them as common fields, and add a new
      equi-join condition to the ON clause.
    */
7251
    if (nj_col_2 && (!using_fields ||is_using_column_1))
unknown's avatar
unknown committed
7252 7253 7254 7255 7256 7257
    {
      Item *item_1=   nj_col_1->create_item(thd);
      Item *item_2=   nj_col_2->create_item(thd);
      Field *field_1= nj_col_1->field();
      Field *field_2= nj_col_2->field();
      Item_ident *item_ident_1, *item_ident_2;
7258 7259 7260 7261 7262
      Item_func_eq *eq_cond;

      if (!item_1 || !item_2)
        goto err;                               // out of memory

unknown's avatar
unknown committed
7263
      /*
7264
        The following assert checks that the two created items are of
unknown's avatar
unknown committed
7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288
        type Item_ident.
      */
      DBUG_ASSERT(!thd->lex->current_select->no_wrap_view_item);
      /*
        In the case of no_wrap_view_item == 0, the created items must be
        of sub-classes of Item_ident.
      */
      DBUG_ASSERT(item_1->type() == Item::FIELD_ITEM ||
                  item_1->type() == Item::REF_ITEM);
      DBUG_ASSERT(item_2->type() == Item::FIELD_ITEM ||
                  item_2->type() == Item::REF_ITEM);

      /*
        We need to cast item_1,2 to Item_ident, because we need to hook name
        resolution contexts specific to each item.
      */
      item_ident_1= (Item_ident*) item_1;
      item_ident_2= (Item_ident*) item_2;
      /*
        Create and hook special name resolution contexts to each item in the
        new join condition . We need this to both speed-up subsequent name
        resolution of these items, and to enable proper name resolution of
        the items during the execute phase of PS.
      */
7289 7290
      if (set_new_item_local_context(thd, item_ident_1, nj_col_1->table_ref) ||
          set_new_item_local_context(thd, item_ident_2, nj_col_2->table_ref))
unknown's avatar
unknown committed
7291 7292
        goto err;

7293 7294
      if (!(eq_cond= new Item_func_eq(item_ident_1, item_ident_2)))
        goto err;                               /* Out of memory. */
unknown's avatar
unknown committed
7295 7296 7297 7298 7299 7300

      /*
        Add the new equi-join condition to the ON clause. Notice that
        fix_fields() is applied to all ON conditions in setup_conds()
        so we don't do it here.
       */
7301 7302 7303
      add_join_on((table_ref_1->outer_join & JOIN_TYPE_RIGHT ?
                   table_ref_1 : table_ref_2),
                  eq_cond);
unknown's avatar
unknown committed
7304 7305

      nj_col_1->is_common= nj_col_2->is_common= TRUE;
7306 7307 7308 7309 7310 7311 7312
      DBUG_PRINT ("info", ("%s.%s and %s.%s are common", 
                           nj_col_1->table_name() ? 
                             nj_col_1->table_name() : "", 
                           nj_col_1->name(),
                           nj_col_2->table_name() ? 
                             nj_col_2->table_name() : "", 
                           nj_col_2->name()));
unknown's avatar
unknown committed
7313 7314 7315

      if (field_1)
      {
unknown's avatar
unknown committed
7316
        TABLE *table_1= nj_col_1->table_ref->table;
unknown's avatar
unknown committed
7317
        /* Mark field_1 used for table cache. */
7318
        bitmap_set_bit(table_1->read_set, field_1->field_index);
7319
        table_1->covering_keys.intersect(field_1->part_of_key);
7320
        table_1->merge_keys.merge(field_1->part_of_key);
unknown's avatar
unknown committed
7321 7322 7323
      }
      if (field_2)
      {
unknown's avatar
unknown committed
7324
        TABLE *table_2= nj_col_2->table_ref->table;
unknown's avatar
unknown committed
7325
        /* Mark field_2 used for table cache. */
7326
        bitmap_set_bit(table_2->read_set, field_2->field_index);
7327
        table_2->covering_keys.intersect(field_2->part_of_key);
7328
        table_2->merge_keys.merge(field_2->part_of_key);
unknown's avatar
unknown committed
7329 7330 7331 7332 7333 7334
      }

      if (using_fields != NULL)
        ++(*found_using_fields);
    }
  }
unknown's avatar
unknown committed
7335 7336
  if (leaf_1)
    leaf_1->is_join_columns_complete= TRUE;
unknown's avatar
unknown committed
7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348

  /*
    Everything is OK.
    Notice that at this point there may be some column names in the USING
    clause that are not among the common columns. This is an SQL error and
    we check for this error in store_natural_using_join_columns() when
    (found_using_fields < length(join_using_fields)).
  */
  result= FALSE;

err:
  if (arena)
unknown's avatar
unknown committed
7349
    thd->restore_active_arena(arena, &backup);
unknown's avatar
unknown committed
7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385
  DBUG_RETURN(result);
}



/*
  Materialize and store the row type of NATURAL/USING join.

  SYNOPSIS
    store_natural_using_join_columns()
    thd                current thread
    natural_using_join the table reference of the NATURAL/USING join
    table_ref_1        the first (left) operand (of a NATURAL/USING join).
    table_ref_2        the second (right) operand (of a NATURAL/USING join).
    using_fields       if the join is JOIN...USING - the join columns,
                       if NATURAL join, then NULL
    found_using_fields number of fields from the USING clause that were
                       found among the common fields

  DESCRIPTION
    Iterate over the columns of both join operands and sort and store
    all columns into the 'join_columns' list of natural_using_join
    where the list is formed by three parts:
      part1: The coalesced columns of table_ref_1 and table_ref_2,
             sorted according to the column order of the first table.
      part2: The other columns of the first table, in the order in
             which they were defined in CREATE TABLE.
      part3: The other columns of the second table, in the order in
             which they were defined in CREATE TABLE.
    Time complexity - O(N1+N2), where Ni = length(table_ref_i).

  IMPLEMENTATION
    The procedure assumes that mark_common_columns() has been called
    for the join that is being processed.

  RETURN
7386 7387
    TRUE    error: Some common column is ambiguous
    FALSE   OK
unknown's avatar
unknown committed
7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400
*/

static bool
store_natural_using_join_columns(THD *thd, TABLE_LIST *natural_using_join,
                                 TABLE_LIST *table_ref_1,
                                 TABLE_LIST *table_ref_2,
                                 List<String> *using_fields,
                                 uint found_using_fields)
{
  Field_iterator_table_ref it_1, it_2;
  Natural_join_column *nj_col_1, *nj_col_2;
  Query_arena *arena, backup;
  bool result= TRUE;
7401
  List<Natural_join_column> *non_join_columns;
unknown's avatar
unknown committed
7402 7403
  DBUG_ENTER("store_natural_using_join_columns");

7404 7405
  DBUG_ASSERT(!natural_using_join->join_columns);

unknown's avatar
unknown committed
7406
  arena= thd->activate_stmt_arena_if_needed(&backup);
unknown's avatar
unknown committed
7407

7408 7409
  if (!(non_join_columns= new List<Natural_join_column>) ||
      !(natural_using_join->join_columns= new List<Natural_join_column>))
unknown's avatar
unknown committed
7410 7411 7412 7413 7414
    goto err;

  /* Append the columns of the first join operand. */
  for (it_1.set(table_ref_1); !it_1.end_of_fields(); it_1.next())
  {
7415
    nj_col_1= it_1.get_natural_column_ref();
unknown's avatar
unknown committed
7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436
    if (nj_col_1->is_common)
    {
      natural_using_join->join_columns->push_back(nj_col_1);
      /* Reset the common columns for the next call to mark_common_columns. */
      nj_col_1->is_common= FALSE;
    }
    else
      non_join_columns->push_back(nj_col_1);
  }

  /*
    Check that all columns in the USING clause are among the common
    columns. If this is not the case, report the first one that was
    not found in an error.
  */
  if (using_fields && found_using_fields < using_fields->elements)
  {
    String *using_field_name;
    List_iterator_fast<String> using_fields_it(*using_fields);
    while ((using_field_name= using_fields_it++))
    {
7437
      const char *using_field_name_ptr= using_field_name->c_ptr();
unknown's avatar
unknown committed
7438 7439 7440
      List_iterator_fast<Natural_join_column>
        it(*(natural_using_join->join_columns));
      Natural_join_column *common_field;
7441 7442

      for (;;)
unknown's avatar
unknown committed
7443
      {
7444 7445 7446 7447 7448 7449 7450
        /* If reached the end of fields, and none was found, report error. */
        if (!(common_field= it++))
        {
          my_error(ER_BAD_FIELD_ERROR, MYF(0), using_field_name_ptr,
                   current_thd->where);
          goto err;
        }
unknown's avatar
unknown committed
7451 7452
        if (!my_strcasecmp(system_charset_info,
                           common_field->name(), using_field_name_ptr))
7453
          break;                                // Found match
unknown's avatar
unknown committed
7454 7455 7456 7457 7458 7459 7460
      }
    }
  }

  /* Append the non-equi-join columns of the second join operand. */
  for (it_2.set(table_ref_2); !it_2.end_of_fields(); it_2.next())
  {
7461
    nj_col_2= it_2.get_natural_column_ref();
unknown's avatar
unknown committed
7462 7463 7464
    if (!nj_col_2->is_common)
      non_join_columns->push_back(nj_col_2);
    else
7465
    {
unknown's avatar
unknown committed
7466 7467
      /* Reset the common columns for the next call to mark_common_columns. */
      nj_col_2->is_common= FALSE;
7468
    }
unknown's avatar
unknown committed
7469 7470 7471 7472 7473 7474 7475 7476 7477 7478
  }

  if (non_join_columns->elements > 0)
    natural_using_join->join_columns->concat(non_join_columns);
  natural_using_join->is_join_columns_complete= TRUE;

  result= FALSE;

err:
  if (arena)
unknown's avatar
unknown committed
7479
    thd->restore_active_arena(arena, &backup);
unknown's avatar
unknown committed
7480 7481 7482
  DBUG_RETURN(result);
}

7483

unknown's avatar
unknown committed
7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509
/*
  Precompute and store the row types of the top-most NATURAL/USING joins.

  SYNOPSIS
    store_top_level_join_columns()
    thd            current thread
    table_ref      nested join or table in a FROM clause
    left_neighbor  neighbor table reference to the left of table_ref at the
                   same level in the join tree
    right_neighbor neighbor table reference to the right of table_ref at the
                   same level in the join tree

  DESCRIPTION
    The procedure performs a post-order traversal of a nested join tree
    and materializes the row types of NATURAL/USING joins in a
    bottom-up manner until it reaches the TABLE_LIST elements that
    represent the top-most NATURAL/USING joins. The procedure should be
    applied to each element of SELECT_LEX::top_join_list (i.e. to each
    top-level element of the FROM clause).

  IMPLEMENTATION
    Notice that the table references in the list nested_join->join_list
    are in reverse order, thus when we iterate over it, we are moving
    from the right to the left in the FROM clause.

  RETURN
7510 7511
    TRUE   Error
    FALSE  OK
unknown's avatar
unknown committed
7512 7513 7514 7515 7516 7517 7518
*/

static bool
store_top_level_join_columns(THD *thd, TABLE_LIST *table_ref,
                             TABLE_LIST *left_neighbor,
                             TABLE_LIST *right_neighbor)
{
unknown's avatar
unknown committed
7519 7520 7521
  Query_arena *arena, backup;
  bool result= TRUE;

unknown's avatar
unknown committed
7522
  DBUG_ENTER("store_top_level_join_columns");
7523

unknown's avatar
unknown committed
7524
  arena= thd->activate_stmt_arena_if_needed(&backup);
unknown's avatar
unknown committed
7525

unknown's avatar
unknown committed
7526 7527 7528 7529
  /* Call the procedure recursively for each nested table reference. */
  if (table_ref->nested_join)
  {
    List_iterator_fast<TABLE_LIST> nested_it(table_ref->nested_join->join_list);
unknown's avatar
unknown committed
7530 7531 7532 7533
    TABLE_LIST *same_level_left_neighbor= nested_it++;
    TABLE_LIST *same_level_right_neighbor= NULL;
    /* Left/right-most neighbors, possibly at higher levels in the join tree. */
    TABLE_LIST *real_left_neighbor, *real_right_neighbor;
7534

unknown's avatar
unknown committed
7535
    while (same_level_left_neighbor)
unknown's avatar
unknown committed
7536
    {
unknown's avatar
unknown committed
7537 7538
      TABLE_LIST *cur_table_ref= same_level_left_neighbor;
      same_level_left_neighbor= nested_it++;
7539 7540 7541 7542
      /*
        The order of RIGHT JOIN operands is reversed in 'join list' to
        transform it into a LEFT JOIN. However, in this procedure we need
        the join operands in their lexical order, so below we reverse the
unknown's avatar
unknown committed
7543 7544 7545 7546 7547
        join operands. Notice that this happens only in the first loop,
        and not in the second one, as in the second loop
        same_level_left_neighbor == NULL.
        This is the correct behavior, because the second loop sets
        cur_table_ref reference correctly after the join operands are
7548 7549
        swapped in the first loop.
      */
unknown's avatar
unknown committed
7550
      if (same_level_left_neighbor &&
7551 7552 7553 7554
          cur_table_ref->outer_join & JOIN_TYPE_RIGHT)
      {
        /* This can happen only for JOIN ... ON. */
        DBUG_ASSERT(table_ref->nested_join->join_list.elements == 2);
unknown's avatar
unknown committed
7555
        swap_variables(TABLE_LIST*, same_level_left_neighbor, cur_table_ref);
7556 7557
      }

unknown's avatar
unknown committed
7558 7559 7560 7561 7562 7563 7564 7565 7566
      /*
        Pick the parent's left and right neighbors if there are no immediate
        neighbors at the same level.
      */
      real_left_neighbor=  (same_level_left_neighbor) ?
                           same_level_left_neighbor : left_neighbor;
      real_right_neighbor= (same_level_right_neighbor) ?
                           same_level_right_neighbor : right_neighbor;

7567 7568
      if (cur_table_ref->nested_join &&
          store_top_level_join_columns(thd, cur_table_ref,
unknown's avatar
unknown committed
7569
                                       real_left_neighbor, real_right_neighbor))
unknown's avatar
unknown committed
7570
        goto err;
unknown's avatar
unknown committed
7571
      same_level_right_neighbor= cur_table_ref;
unknown's avatar
unknown committed
7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601
    }
  }

  /*
    If this is a NATURAL/USING join, materialize its result columns and
    convert to a JOIN ... ON.
  */
  if (table_ref->is_natural_join)
  {
    DBUG_ASSERT(table_ref->nested_join &&
                table_ref->nested_join->join_list.elements == 2);
    List_iterator_fast<TABLE_LIST> operand_it(table_ref->nested_join->join_list);
    /*
      Notice that the order of join operands depends on whether table_ref
      represents a LEFT or a RIGHT join. In a RIGHT join, the operands are
      in inverted order.
     */
    TABLE_LIST *table_ref_2= operand_it++; /* Second NATURAL join operand.*/
    TABLE_LIST *table_ref_1= operand_it++; /* First NATURAL join operand. */
    List<String> *using_fields= table_ref->join_using_fields;
    uint found_using_fields;

    /*
      The two join operands were interchanged in the parser, change the order
      back for 'mark_common_columns'.
    */
    if (table_ref_2->outer_join & JOIN_TYPE_RIGHT)
      swap_variables(TABLE_LIST*, table_ref_1, table_ref_2);
    if (mark_common_columns(thd, table_ref_1, table_ref_2,
                            using_fields, &found_using_fields))
unknown's avatar
unknown committed
7602
      goto err;
unknown's avatar
unknown committed
7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613

    /*
      Swap the join operands back, so that we pick the columns of the second
      one as the coalesced columns. In this way the coalesced columns are the
      same as of an equivalent LEFT JOIN.
    */
    if (table_ref_1->outer_join & JOIN_TYPE_RIGHT)
      swap_variables(TABLE_LIST*, table_ref_1, table_ref_2);
    if (store_natural_using_join_columns(thd, table_ref, table_ref_1,
                                         table_ref_2, using_fields,
                                         found_using_fields))
unknown's avatar
unknown committed
7614
      goto err;
unknown's avatar
unknown committed
7615 7616 7617 7618 7619 7620 7621 7622 7623

    /*
      Change NATURAL JOIN to JOIN ... ON. We do this for both operands
      because either one of them or the other is the one with the
      natural join flag because RIGHT joins are transformed into LEFT,
      and the two tables may be reordered.
    */
    table_ref_1->natural_join= table_ref_2->natural_join= NULL;

unknown's avatar
unknown committed
7624 7625 7626 7627 7628
    /* Add a TRUE condition to outer joins that have no common columns. */
    if (table_ref_2->outer_join &&
        !table_ref_1->on_expr && !table_ref_2->on_expr)
      table_ref_2->on_expr= new Item_int((longlong) 1,1);   /* Always true. */

unknown's avatar
unknown committed
7629 7630 7631
    /* Change this table reference to become a leaf for name resolution. */
    if (left_neighbor)
    {
7632
      TABLE_LIST *last_leaf_on_the_left;
unknown's avatar
unknown committed
7633 7634 7635 7636 7637
      last_leaf_on_the_left= left_neighbor->last_leaf_for_name_resolution();
      last_leaf_on_the_left->next_name_resolution_table= table_ref;
    }
    if (right_neighbor)
    {
7638
      TABLE_LIST *first_leaf_on_the_right;
unknown's avatar
unknown committed
7639 7640 7641 7642 7643 7644
      first_leaf_on_the_right= right_neighbor->first_leaf_for_name_resolution();
      table_ref->next_name_resolution_table= first_leaf_on_the_right;
    }
    else
      table_ref->next_name_resolution_table= NULL;
  }
unknown's avatar
unknown committed
7645 7646 7647 7648
  result= FALSE; /* All is OK. */

err:
  if (arena)
unknown's avatar
unknown committed
7649
    thd->restore_active_arena(arena, &backup);
unknown's avatar
unknown committed
7650
  DBUG_RETURN(result);
unknown's avatar
unknown committed
7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674
}


/*
  Compute and store the row types of the top-most NATURAL/USING joins
  in a FROM clause.

  SYNOPSIS
    setup_natural_join_row_types()
    thd          current thread
    from_clause  list of top-level table references in a FROM clause

  DESCRIPTION
    Apply the procedure 'store_top_level_join_columns' to each of the
    top-level table referencs of the FROM clause. Adjust the list of tables
    for name resolution - context->first_name_resolution_table to the
    top-most, lef-most NATURAL/USING join.

  IMPLEMENTATION
    Notice that the table references in 'from_clause' are in reverse
    order, thus when we iterate over it, we are moving from the right
    to the left in the FROM clause.

  RETURN
7675 7676
    TRUE   Error
    FALSE  OK
unknown's avatar
unknown committed
7677
*/
7678 7679
static bool setup_natural_join_row_types(THD *thd,
                                         List<TABLE_LIST> *from_clause,
unknown's avatar
unknown committed
7680 7681
                                         Name_resolution_context *context)
{
7682
  DBUG_ENTER("setup_natural_join_row_types");
unknown's avatar
unknown committed
7683 7684
  thd->where= "from clause";
  if (from_clause->elements == 0)
7685
    DBUG_RETURN(false); /* We come here in the case of UNIONs. */
unknown's avatar
unknown committed
7686 7687 7688 7689

  List_iterator_fast<TABLE_LIST> table_ref_it(*from_clause);
  TABLE_LIST *table_ref; /* Current table reference. */
  /* Table reference to the left of the current. */
7690
  TABLE_LIST *left_neighbor;
unknown's avatar
unknown committed
7691 7692 7693
  /* Table reference to the right of the current. */
  TABLE_LIST *right_neighbor= NULL;

7694 7695
  /* Note that tables in the list are in reversed order */
  for (left_neighbor= table_ref_it++; left_neighbor ; )
unknown's avatar
unknown committed
7696 7697 7698
  {
    table_ref= left_neighbor;
    left_neighbor= table_ref_it++;
7699 7700 7701 7702 7703
    /* 
      Do not redo work if already done:
      1) for stored procedures,
      2) for multitable update after lock failure and table reopening.
    */
7704
    if (context->select_lex->first_natural_join_processing)
unknown's avatar
unknown committed
7705
    {
7706 7707
      if (store_top_level_join_columns(thd, table_ref,
                                       left_neighbor, right_neighbor))
7708
        DBUG_RETURN(true);
7709 7710 7711 7712 7713 7714
      if (left_neighbor)
      {
        TABLE_LIST *first_leaf_on_the_right;
        first_leaf_on_the_right= table_ref->first_leaf_for_name_resolution();
        left_neighbor->next_name_resolution_table= first_leaf_on_the_right;
      }
unknown's avatar
unknown committed
7715 7716 7717 7718 7719 7720 7721
    }
    right_neighbor= table_ref;
  }

  /*
    Store the top-most, left-most NATURAL/USING join, so that we start
    the search from that one instead of context->table_list. At this point
7722
    right_neighbor points to the left-most top-level table reference in the
unknown's avatar
unknown committed
7723 7724 7725 7726 7727
    FROM clause.
  */
  DBUG_ASSERT(right_neighbor);
  context->first_name_resolution_table=
    right_neighbor->first_leaf_for_name_resolution();
7728
  context->select_lex->first_natural_join_processing= false;
unknown's avatar
unknown committed
7729

7730
  DBUG_RETURN (false);
unknown's avatar
unknown committed
7731 7732 7733
}


unknown's avatar
unknown committed
7734
/****************************************************************************
7735
** Expand all '*' in given fields
unknown's avatar
unknown committed
7736 7737
****************************************************************************/

7738 7739 7740
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
	       List<Item> *sum_func_list,
	       uint wild_num)
unknown's avatar
unknown committed
7741
{
7742
  if (!wild_num)
7743
    return(0);
7744

7745
  Item *item;
unknown's avatar
unknown committed
7746
  List_iterator<Item> it(fields);
unknown's avatar
unknown committed
7747
  Query_arena *arena, backup;
7748
  DBUG_ENTER("setup_wild");
unknown's avatar
unknown committed
7749 7750

  /*
7751 7752
    Don't use arena if we are not in prepared statements or stored procedures
    For PS/SP we have to use arena to remember the changes
unknown's avatar
unknown committed
7753
  */
unknown's avatar
unknown committed
7754
  arena= thd->activate_stmt_arena_if_needed(&backup);
7755

7756
  thd->lex->current_select->cur_pos_in_select_list= 0;
unknown's avatar
unknown committed
7757
  while (wild_num && (item= it++))
unknown's avatar
VIEW  
unknown committed
7758
  {
7759 7760
    if (item->type() == Item::FIELD_ITEM &&
        ((Item_field*) item)->field_name &&
7761 7762
	((Item_field*) item)->field_name[0] == '*' &&
	!((Item_field*) item)->field)
7763
    {
7764
      uint elem= fields.elements;
unknown's avatar
VIEW  
unknown committed
7765
      bool any_privileges= ((Item_field *) item)->any_privileges;
unknown's avatar
unknown committed
7766 7767 7768 7769 7770 7771 7772 7773 7774
      Item_subselect *subsel= thd->lex->current_select->master_unit()->item;
      if (subsel &&
          subsel->substype() == Item_subselect::EXISTS_SUBS)
      {
        /*
          It is EXISTS(SELECT * ...) and we can replace * by any constant.

          Item_int do not need fix_fields() because it is basic constant.
        */
7775 7776
        it.replace(new Item_int("Not_used", (longlong) 1,
                                MY_INT64_NUM_DECIMAL_DIGITS));
unknown's avatar
unknown committed
7777
      }
7778 7779
      else if (insert_fields(thd, ((Item_field*) item)->context,
                             ((Item_field*) item)->db_name,
unknown's avatar
unknown committed
7780
                             ((Item_field*) item)->table_name, &it,
7781
                             any_privileges))
unknown's avatar
unknown committed
7782 7783
      {
	if (arena)
unknown's avatar
unknown committed
7784
	  thd->restore_active_arena(arena, &backup);
7785
	DBUG_RETURN(-1);
unknown's avatar
unknown committed
7786
      }
7787
      if (sum_func_list)
7788 7789 7790 7791 7792 7793 7794 7795
      {
	/*
	  sum_func_list is a list that has the fields list as a tail.
	  Because of this we have to update the element count also for this
	  list after expanding the '*' entry.
	*/
	sum_func_list->elements+= fields.elements - elem;
      }
7796
      wild_num--;
7797
    }
7798 7799
    else
      thd->lex->current_select->cur_pos_in_select_list++;
7800
  }
7801
  thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
unknown's avatar
unknown committed
7802 7803 7804 7805 7806
  if (arena)
  {
    /* make * substituting permanent */
    SELECT_LEX *select_lex= thd->lex->current_select;
    select_lex->with_wild= 0;
7807 7808 7809 7810 7811 7812 7813
    /*   
      The assignment below is translated to memcpy() call (at least on some
      platforms). memcpy() expects that source and destination areas do not
      overlap. That problem was detected by valgrind. 
    */
    if (&select_lex->item_list != &fields)
      select_lex->item_list= fields;
unknown's avatar
unknown committed
7814

unknown's avatar
unknown committed
7815
    thd->restore_active_arena(arena, &backup);
unknown's avatar
unknown committed
7816
  }
7817
  DBUG_RETURN(0);
7818 7819
}

7820 7821 7822 7823
/****************************************************************************
** Check that all given fields exists and fill struct with current data
****************************************************************************/

7824
bool setup_fields(THD *thd, Item **ref_pointer_array,
7825
                  List<Item> &fields, enum_mark_columns mark_used_columns,
unknown's avatar
unknown committed
7826
                  List<Item> *sum_func_list, bool allow_sum_func)
7827 7828
{
  reg2 Item *item;
7829
  enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
unknown's avatar
unknown committed
7830
  nesting_map save_allow_sum_func= thd->lex->allow_sum_func;
7831
  List_iterator<Item> it(fields);
7832
  bool save_is_item_list_lookup;
7833 7834
  DBUG_ENTER("setup_fields");

7835 7836
  thd->mark_used_columns= mark_used_columns;
  DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
unknown's avatar
unknown committed
7837 7838
  if (allow_sum_func)
    thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level;
7839
  thd->where= THD::DEFAULT_WHERE;
7840 7841
  save_is_item_list_lookup= thd->lex->current_select->is_item_list_lookup;
  thd->lex->current_select->is_item_list_lookup= 0;
7842

7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856
  /*
    To prevent fail on forward lookup we fill it with zerows,
    then if we got pointer on zero after find_item_in_list we will know
    that it is forward lookup.

    There is other way to solve problem: fill array with pointers to list,
    but it will be slower.

    TODO: remove it when (if) we made one list for allfields and
    ref_pointer_array
  */
  if (ref_pointer_array)
    bzero(ref_pointer_array, sizeof(Item *) * fields.elements);

7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872
  /*
    We call set_entry() there (before fix_fields() of the whole list of field
    items) because:
    1) the list of field items has same order as in the query, and the
       Item_func_get_user_var item may go before the Item_func_set_user_var:
          SELECT @a, @a := 10 FROM t;
    2) The entry->update_query_id value controls constantness of
       Item_func_get_user_var items, so in presence of Item_func_set_user_var
       items we have to refresh their entries before fixing of
       Item_func_get_user_var items.
  */
  List_iterator<Item_func_set_user_var> li(thd->lex->set_var_list);
  Item_func_set_user_var *var;
  while ((var= li++))
    var->set_entry(thd, FALSE);

unknown's avatar
unknown committed
7873
  Item **ref= ref_pointer_array;
7874
  thd->lex->current_select->cur_pos_in_select_list= 0;
unknown's avatar
unknown committed
7875
  while ((item= it++))
7876
  {
7877
    if ((!item->fixed && item->fix_fields(thd, it.ref())) ||
unknown's avatar
unknown committed
7878
	(item= *(it.ref()))->check_cols(1))
unknown's avatar
unknown committed
7879
    {
7880
      thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
unknown's avatar
unknown committed
7881
      thd->lex->allow_sum_func= save_allow_sum_func;
7882 7883
      thd->mark_used_columns= save_mark_used_columns;
      DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
unknown's avatar
unknown committed
7884
      DBUG_RETURN(TRUE); /* purecov: inspected */
unknown's avatar
unknown committed
7885
    }
unknown's avatar
unknown committed
7886 7887
    if (ref)
      *(ref++)= item;
7888 7889
    if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
	sum_func_list)
7890
      item->split_sum_func(thd, ref_pointer_array, *sum_func_list);
unknown's avatar
unknown committed
7891
    thd->used_tables|= item->used_tables();
7892
    thd->lex->current_select->cur_pos_in_select_list++;
7893
  }
7894
  thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
7895 7896
  thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;

unknown's avatar
unknown committed
7897
  thd->lex->allow_sum_func= save_allow_sum_func;
7898 7899
  thd->mark_used_columns= save_mark_used_columns;
  DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
7900
  DBUG_RETURN(test(thd->is_error()));
7901
}
7902

7903

7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918
/*
  make list of leaves of join table tree

  SYNOPSIS
    make_leaves_list()
    list    pointer to pointer on list first element
    tables  table list

  RETURN pointer on pointer to next_leaf of last element
*/

TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
{
  for (TABLE_LIST *table= tables; table; table= table->next_local)
  {
7919 7920 7921 7922 7923 7924
    if (table->merge_underlying_list)
    {
      DBUG_ASSERT(table->view &&
                  table->effective_algorithm == VIEW_ALGORITHM_MERGE);
      list= make_leaves_list(list, table->merge_underlying_list);
    }
7925 7926 7927 7928 7929 7930 7931 7932 7933
    else
    {
      *list= table;
      list= &table->next_leaf;
    }
  }
  return list;
}

7934
/*
unknown's avatar
unknown committed
7935 7936 7937 7938
  prepare tables

  SYNOPSIS
    setup_tables()
unknown's avatar
unknown committed
7939
    thd		  Thread handler
7940
    context       name resolution contest to setup table list there
unknown's avatar
unknown committed
7941 7942 7943
    from_clause   Top-level list of table references in the FROM clause
    tables	  Table list (select_lex->table_list)
    leaves        List of join table leaves list (select_lex->leaf_tables)
unknown's avatar
unknown committed
7944 7945
    refresh       It is onle refresh for subquery
    select_insert It is SELECT ... INSERT command
unknown's avatar
unknown committed
7946

unknown's avatar
unknown committed
7947 7948
  NOTE
    Check also that the 'used keys' and 'ignored keys' exists and set up the
unknown's avatar
unknown committed
7949 7950 7951 7952
    table structure accordingly.
    Create a list of leaf tables. For queries with NATURAL/USING JOINs,
    compute the row types of the top most natural/using join table references
    and link these into a list of table references for name resolution.
7953

unknown's avatar
unknown committed
7954 7955
    This has to be called for all tables that are used by items, as otherwise
    table->map is not set and all Item_field will be regarded as const items.
unknown's avatar
VIEW  
unknown committed
7956

unknown's avatar
unknown committed
7957
  RETURN
unknown's avatar
unknown committed
7958
    FALSE ok;  In this case *map will includes the chosen index
unknown's avatar
unknown committed
7959
    TRUE  error
7960 7961
*/

7962
bool setup_tables(THD *thd, Name_resolution_context *context,
unknown's avatar
unknown committed
7963
                  List<TABLE_LIST> *from_clause, TABLE_LIST *tables,
7964
                  TABLE_LIST **leaves, bool select_insert)
7965
{
unknown's avatar
unknown committed
7966
  uint tablenr= 0;
7967
  DBUG_ENTER("setup_tables");
7968

7969 7970
  DBUG_ASSERT ((select_insert && !tables->next_name_resolution_table) || !tables || 
               (context->table_list && context->first_name_resolution_table));
unknown's avatar
unknown committed
7971 7972
  /*
    this is used for INSERT ... SELECT.
7973
    For select we setup tables except first (and its underlying tables)
unknown's avatar
unknown committed
7974 7975 7976 7977
  */
  TABLE_LIST *first_select_table= (select_insert ?
                                   tables->next_local:
                                   0);
7978 7979 7980
  if (!(*leaves))
    make_leaves_list(leaves, tables);

unknown's avatar
unknown committed
7981 7982
  TABLE_LIST *table_list;
  for (table_list= *leaves;
unknown's avatar
VIEW  
unknown committed
7983
       table_list;
7984
       table_list= table_list->next_leaf, tablenr++)
unknown's avatar
unknown committed
7985
  {
unknown's avatar
unknown committed
7986
    TABLE *table= table_list->table;
unknown's avatar
unknown committed
7987
    table->pos_in_table_list= table_list;
unknown's avatar
unknown committed
7988
    if (first_select_table &&
7989
        table_list->top_table() == first_select_table)
unknown's avatar
unknown committed
7990 7991 7992 7993 7994
    {
      /* new counting for SELECT of INSERT ... SELECT command */
      first_select_table= 0;
      tablenr= 0;
    }
unknown's avatar
unknown committed
7995
    setup_table_map(table, table_list, tablenr);
7996 7997
    if (table_list->process_index_hints(table))
      DBUG_RETURN(1);
unknown's avatar
unknown committed
7998 7999 8000
  }
  if (tablenr > MAX_TABLES)
  {
Guilhem Bichot's avatar
Guilhem Bichot committed
8001
    my_error(ER_TOO_MANY_TABLES,MYF(0), static_cast<int>(MAX_TABLES));
8002
    DBUG_RETURN(1);
unknown's avatar
unknown committed
8003
  }
unknown's avatar
unknown committed
8004
  for (table_list= tables;
8005 8006
       table_list;
       table_list= table_list->next_local)
8007
  {
8008
    if (table_list->merge_underlying_list)
8009
    {
8010 8011
      DBUG_ASSERT(table_list->view &&
                  table_list->effective_algorithm == VIEW_ALGORITHM_MERGE);
unknown's avatar
unknown committed
8012
      Query_arena *arena= thd->stmt_arena, backup;
8013 8014 8015 8016
      bool res;
      if (arena->is_conventional())
        arena= 0;                                   // For easier test
      else
unknown's avatar
unknown committed
8017
        thd->set_n_backup_active_arena(arena, &backup);
8018
      res= table_list->setup_underlying(thd);
8019
      if (arena)
unknown's avatar
unknown committed
8020
        thd->restore_active_arena(arena, &backup);
8021 8022 8023
      if (res)
        DBUG_RETURN(1);
    }
8024
  }
unknown's avatar
unknown committed
8025 8026 8027 8028 8029

  /* Precompute and store the row types of NATURAL/USING joins. */
  if (setup_natural_join_row_types(thd, from_clause, context))
    DBUG_RETURN(1);

8030
  DBUG_RETURN(0);
unknown's avatar
unknown committed
8031
}
8032

unknown's avatar
unknown committed
8033

8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060
/*
  prepare tables and check access for the view tables

  SYNOPSIS
    setup_tables_and_check_view_access()
    thd		  Thread handler
    context       name resolution contest to setup table list there
    from_clause   Top-level list of table references in the FROM clause
    tables	  Table list (select_lex->table_list)
    conds	  Condition of current SELECT (can be changed by VIEW)
    leaves        List of join table leaves list (select_lex->leaf_tables)
    refresh       It is onle refresh for subquery
    select_insert It is SELECT ... INSERT command
    want_access   what access is needed

  NOTE
    a wrapper for check_tables that will also check the resulting
    table leaves list for access to all the tables that belong to a view

  RETURN
    FALSE ok;  In this case *map will include the chosen index
    TRUE  error
*/
bool setup_tables_and_check_access(THD *thd, 
                                   Name_resolution_context *context,
                                   List<TABLE_LIST> *from_clause,
                                   TABLE_LIST *tables,
unknown's avatar
unknown committed
8061
                                   TABLE_LIST **leaves,
8062
                                   bool select_insert,
8063
                                   ulong want_access_first,
8064 8065
                                   ulong want_access)
{
unknown's avatar
unknown committed
8066
  TABLE_LIST *leaves_tmp= NULL;
8067
  bool first_table= true;
8068

unknown's avatar
unknown committed
8069 8070
  if (setup_tables(thd, context, from_clause, tables,
                   &leaves_tmp, select_insert))
8071 8072
    return TRUE;

unknown's avatar
unknown committed
8073 8074
  if (leaves)
    *leaves= leaves_tmp;
8075 8076

  for (; leaves_tmp; leaves_tmp= leaves_tmp->next_leaf)
unknown's avatar
unknown committed
8077
  {
8078
    if (leaves_tmp->belong_to_view && 
8079
        check_single_table_access(thd, first_table ? want_access_first :
8080
                                  want_access, leaves_tmp, FALSE))
8081 8082 8083 8084
    {
      tables->hide_view_error(thd);
      return TRUE;
    }
8085
    first_table= 0;
unknown's avatar
unknown committed
8086
  }
8087 8088 8089 8090
  return FALSE;
}


8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105
/*
   Create a key_map from a list of index names

   SYNOPSIS
     get_key_map_from_key_list()
     map		key_map to fill in
     table		Table
     index_list		List of index names

   RETURN
     0	ok;  In this case *map will includes the choosed index
     1	error
*/

bool get_key_map_from_key_list(key_map *map, TABLE *table,
8106
                               List<String> *index_list)
unknown's avatar
unknown committed
8107
{
unknown's avatar
unknown committed
8108
  List_iterator_fast<String> it(*index_list);
unknown's avatar
unknown committed
8109 8110
  String *name;
  uint pos;
8111 8112

  map->clear_all();
unknown's avatar
unknown committed
8113 8114
  while ((name=it++))
  {
8115 8116 8117
    if (table->s->keynames.type_names == 0 ||
        (pos= find_type(&table->s->keynames, name->ptr(),
                        name->length(), 1)) <=
8118
        0)
unknown's avatar
unknown committed
8119
    {
8120
      my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), name->c_ptr(),
unknown's avatar
unknown committed
8121
	       table->pos_in_table_list->alias);
8122
      map->set_all();
8123
      return 1;
unknown's avatar
unknown committed
8124
    }
8125
    map->set_bit(pos-1);
unknown's avatar
unknown committed
8126
  }
8127
  return 0;
unknown's avatar
unknown committed
8128 8129
}

8130

8131 8132 8133 8134 8135 8136
/*
  Drops in all fields instead of current '*' field

  SYNOPSIS
    insert_fields()
    thd			Thread handler
8137
    context             Context for name resolution
8138 8139 8140 8141 8142 8143 8144
    db_name		Database name in case of 'database_name.table_name.*'
    table_name		Table name in case of 'table_name.*'
    it			Pointer to '*'
    any_privileges	0 If we should ensure that we have SELECT privileges
		          for all columns
                        1 If any privilege is ok
  RETURN
8145
    0	ok     'it' is updated to point at last inserted
unknown's avatar
unknown committed
8146
    1	error.  Error message is generated but not sent to client
8147
*/
unknown's avatar
unknown committed
8148

unknown's avatar
unknown committed
8149
bool
8150
insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
unknown's avatar
VIEW  
unknown committed
8151
	      const char *table_name, List_iterator<Item> *it,
8152
              bool any_privileges)
unknown's avatar
unknown committed
8153
{
unknown's avatar
unknown committed
8154 8155
  Field_iterator_table_ref field_iterator;
  bool found;
unknown's avatar
unknown committed
8156
  char name_buff[NAME_LEN+1];
unknown's avatar
unknown committed
8157
  DBUG_ENTER("insert_fields");
unknown's avatar
unknown committed
8158
  DBUG_PRINT("arena", ("stmt arena: 0x%lx", (ulong)thd->stmt_arena));
unknown's avatar
unknown committed
8159

8160 8161
  if (db_name && lower_case_table_names)
  {
unknown's avatar
unknown committed
8162 8163 8164 8165 8166
    /*
      convert database to lower case for comparison
      We can't do this in Item_field as this would change the
      'name' of the item which may be used in the select list
    */
unknown's avatar
unknown committed
8167
    strmake(name_buff, db_name, sizeof(name_buff)-1);
unknown's avatar
unknown committed
8168
    my_casedn_str(files_charset_info, name_buff);
unknown's avatar
unknown committed
8169
    db_name= name_buff;
8170 8171
  }

unknown's avatar
unknown committed
8172
  found= FALSE;
8173 8174 8175 8176 8177 8178 8179 8180

  /*
    If table names are qualified, then loop over all tables used in the query,
    else treat natural joins as leaves and do not iterate over their underlying
    tables.
  */
  for (TABLE_LIST *tables= (table_name ? context->table_list :
                            context->first_name_resolution_table);
8181
       tables;
8182 8183 8184
       tables= (table_name ? tables->next_local :
                tables->next_name_resolution_table)
       )
unknown's avatar
unknown committed
8185
  {
8186 8187 8188
    Field *field;
    TABLE *table= tables->table;

unknown's avatar
unknown committed
8189 8190
    DBUG_ASSERT(tables->is_leaf_for_name_resolution());

8191 8192
    if ((table_name && my_strcasecmp(table_alias_charset, table_name,
                                    tables->alias)) ||
8193 8194
        (db_name && strcmp(tables->db,db_name)))
      continue;
unknown's avatar
unknown committed
8195

unknown's avatar
unknown committed
8196
#ifndef NO_EMBEDDED_ACCESS_CHECKS
8197 8198 8199 8200 8201 8202 8203 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222
    /* 
       Ensure that we have access rights to all fields to be inserted. Under
       some circumstances, this check may be skipped.

       - If any_privileges is true, skip the check.

       - If the SELECT privilege has been found as fulfilled already for both
         the TABLE and TABLE_LIST objects (and both of these exist, of
         course), the check is skipped.

       - If the SELECT privilege has been found fulfilled for the TABLE object
         and the TABLE_LIST represents a derived table other than a view (see
         below), the check is skipped.

       - If the TABLE_LIST object represents a view, we may skip checking if
         the SELECT privilege has been found fulfilled for it, regardless of
         the TABLE object.

       - If there is no TABLE object, the test is skipped if either 
         * the TABLE_LIST does not represent a view, or
         * the SELECT privilege has been found fulfilled.         

       A TABLE_LIST that is not a view may be a subquery, an
       information_schema table, or a nested table reference. See the comment
       for TABLE_LIST.
    */
8223
    if (!((table && !tables->view && (table->grant.privilege & SELECT_ACL)) ||
Staale Smedseng's avatar
Staale Smedseng committed
8224
          (tables->view && (tables->grant.privilege & SELECT_ACL))) &&
unknown's avatar
unknown committed
8225 8226 8227
        !any_privileges)
    {
      field_iterator.set(tables);
8228
      if (check_grant_all_columns(thd, SELECT_ACL, &field_iterator))
unknown's avatar
unknown committed
8229 8230
        DBUG_RETURN(TRUE);
    }
unknown's avatar
unknown committed
8231
#endif
unknown's avatar
VIEW  
unknown committed
8232

unknown's avatar
unknown committed
8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253
    /*
      Update the tables used in the query based on the referenced fields. For
      views and natural joins this update is performed inside the loop below.
    */
    if (table)
      thd->used_tables|= table->map;

    /*
      Initialize a generic field iterator for the current table reference.
      Notice that it is guaranteed that this iterator will iterate over the
      fields of a single table reference, because 'tables' is a leaf (for
      name resolution purposes).
    */
    field_iterator.set(tables);

    for (; !field_iterator.end_of_fields(); field_iterator.next())
    {
      Item *item;

      if (!(item= field_iterator.create_item(thd)))
        DBUG_RETURN(TRUE);
8254 8255 8256 8257
      DBUG_ASSERT(item->fixed);
      /* cache the table for the Item_fields inserted by expanding stars */
      if (item->type() == Item::FIELD_ITEM && tables->cacheable_table)
        ((Item_field *)item)->cached_table= tables;
unknown's avatar
unknown committed
8258 8259

      if (!found)
8260
      {
unknown's avatar
unknown committed
8261
        found= TRUE;
8262
        it->replace(item); /* Replace '*' with the first found item. */
8263
      }
unknown's avatar
VIEW  
unknown committed
8264
      else
unknown's avatar
unknown committed
8265 8266 8267 8268 8269 8270 8271
        it->after(item);   /* Add 'item' to the SELECT list. */

#ifndef NO_EMBEDDED_ACCESS_CHECKS
      /*
        Set privilege information for the fields of newly created views.
        We have that (any_priviliges == TRUE) if and only if we are creating
        a view. In the time of view creation we can't use the MERGE algorithm,
8272 8273 8274
        therefore if 'tables' is itself a view, it is represented by a
        temporary table. Thus in this case we can be sure that 'item' is an
        Item_field.
unknown's avatar
unknown committed
8275 8276
      */
      if (any_privileges)
8277
      {
8278
        DBUG_ASSERT((tables->field_translation == NULL && table) ||
unknown's avatar
unknown committed
8279 8280 8281
                    tables->is_natural_join);
        DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
        Item_field *fld= (Item_field*) item;
8282
        const char *field_table_name= field_iterator.get_table_name();
8283

unknown's avatar
unknown committed
8284 8285 8286
        if (!tables->schema_table && 
            !(fld->have_privileges=
              (get_column_grant(thd, field_iterator.grant(),
8287
                                field_iterator.get_db_name(),
8288
                                field_table_name, fld->field_name) &
unknown's avatar
unknown committed
8289 8290
               VIEW_ANY_ACL)))
        {
8291
          my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), "ANY",
8292 8293
                   thd->security_ctx->priv_user,
                   thd->security_ctx->host_or_ip,
8294
                   field_table_name);
unknown's avatar
unknown committed
8295 8296
          DBUG_RETURN(TRUE);
        }
8297
      }
unknown's avatar
unknown committed
8298
#endif
8299

unknown's avatar
unknown committed
8300
      if ((field= field_iterator.field()))
unknown's avatar
unknown committed
8301
      {
8302 8303
        /* Mark fields as used to allow storage engine to optimze access */
        bitmap_set_bit(field->table->read_set, field->field_index);
unknown's avatar
unknown committed
8304
        if (table)
8305
        {
8306
          table->covering_keys.intersect(field->part_of_key);
8307 8308
          table->merge_keys.merge(field->part_of_key);
        }
unknown's avatar
unknown committed
8309
        if (tables->is_natural_join)
unknown's avatar
unknown committed
8310
        {
unknown's avatar
unknown committed
8311 8312
          TABLE *field_table;
          /*
8313
            In this case we are sure that the column ref will not be created
unknown's avatar
unknown committed
8314
            because it was already created and stored with the natural join.
8315
          */
unknown's avatar
unknown committed
8316
          Natural_join_column *nj_col;
unknown's avatar
unknown committed
8317
          if (!(nj_col= field_iterator.get_natural_column_ref()))
unknown's avatar
unknown committed
8318
            DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
8319
          DBUG_ASSERT(nj_col->table_field);
unknown's avatar
unknown committed
8320 8321
          field_table= nj_col->table_ref->table;
          if (field_table)
unknown's avatar
VIEW  
unknown committed
8322
          {
unknown's avatar
unknown committed
8323
            thd->used_tables|= field_table->map;
8324
            field_table->covering_keys.intersect(field->part_of_key);
8325
            field_table->merge_keys.merge(field->part_of_key);
unknown's avatar
unknown committed
8326
            field_table->used_fields++;
unknown's avatar
VIEW  
unknown committed
8327
          }
unknown's avatar
unknown committed
8328
        }
unknown's avatar
unknown committed
8329
      }
unknown's avatar
unknown committed
8330 8331
      else
        thd->used_tables|= item->used_tables();
8332
      thd->lex->current_select->cur_pos_in_select_list++;
unknown's avatar
unknown committed
8333
    }
unknown's avatar
unknown committed
8334 8335 8336 8337 8338 8339 8340 8341
    /*
      In case of stored tables, all fields are considered as used,
      while in the case of views, the fields considered as used are the
      ones marked in setup_tables during fix_fields of view columns.
      For NATURAL joins, used_tables is updated in the IF above.
    */
    if (table)
      table->used_fields= table->s->fields;
unknown's avatar
unknown committed
8342
  }
8343
  if (found)
unknown's avatar
unknown committed
8344
    DBUG_RETURN(FALSE);
8345

unknown's avatar
unknown committed
8346
  /*
8347 8348 8349
    TODO: in the case when we skipped all columns because there was a
    qualified '*', and all columns were coalesced, we have to give a more
    meaningful message than ER_BAD_TABLE_ERROR.
unknown's avatar
unknown committed
8350
  */
8351
  if (!table_name)
unknown's avatar
unknown committed
8352
    my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0));
8353 8354
  else
    my_error(ER_BAD_TABLE_ERROR, MYF(0), table_name);
unknown's avatar
unknown committed
8355 8356

  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
8357 8358 8359 8360
}


/*
unknown's avatar
unknown committed
8361
  Fix all conditions and outer join expressions.
8362 8363 8364 8365

  SYNOPSIS
    setup_conds()
    thd     thread handler
unknown's avatar
unknown committed
8366 8367 8368 8369 8370 8371 8372 8373 8374 8375
    tables  list of tables for name resolving (select_lex->table_list)
    leaves  list of leaves of join table tree (select_lex->leaf_tables)
    conds   WHERE clause

  DESCRIPTION
    TODO

  RETURN
    TRUE  if some error occured (e.g. out of memory)
    FALSE if all is OK
unknown's avatar
unknown committed
8376 8377
*/

8378 8379
int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
                COND **conds)
unknown's avatar
unknown committed
8380
{
unknown's avatar
unknown committed
8381
  SELECT_LEX *select_lex= thd->lex->current_select;
unknown's avatar
unknown committed
8382
  TABLE_LIST *table= NULL;	// For HP compilers
8383 8384 8385 8386 8387 8388 8389 8390 8391 8392
  /*
    it_is_update set to TRUE when tables of primary SELECT_LEX (SELECT_LEX
    which belong to LEX, i.e. most up SELECT) will be updated by
    INSERT/UPDATE/LOAD
    NOTE: using this condition helps to prevent call of prepare_check_option()
    from subquery of VIEW, because tables of subquery belongs to VIEW
    (see condition before prepare_check_option() call)
  */
  bool it_is_update= (select_lex == &thd->lex->select_lex) &&
    thd->lex->which_check_option_applicable();
8393 8394
  bool save_is_item_list_lookup= select_lex->is_item_list_lookup;
  select_lex->is_item_list_lookup= 0;
unknown's avatar
unknown committed
8395
  DBUG_ENTER("setup_conds");
unknown's avatar
unknown committed
8396

8397 8398
  thd->mark_used_columns= MARK_COLUMNS_READ;
  DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
unknown's avatar
unknown committed
8399
  select_lex->cond_count= 0;
8400
  select_lex->between_count= 0;
unknown's avatar
unknown committed
8401
  select_lex->max_equal_elems= 0;
unknown's avatar
VIEW  
unknown committed
8402

8403 8404 8405 8406 8407 8408
  for (table= tables; table; table= table->next_local)
  {
    if (table->prepare_where(thd, conds, FALSE))
      goto err_no_arena;
  }

unknown's avatar
unknown committed
8409 8410 8411
  if (*conds)
  {
    thd->where="where clause";
8412
    if ((!(*conds)->fixed && (*conds)->fix_fields(thd, conds)) ||
unknown's avatar
unknown committed
8413
	(*conds)->check_cols(1))
8414
      goto err_no_arena;
unknown's avatar
unknown committed
8415 8416
  }

unknown's avatar
unknown committed
8417 8418 8419 8420
  /*
    Apply fix_fields() to all ON clauses at all levels of nesting,
    including the ones inside view definitions.
  */
unknown's avatar
merge  
unknown committed
8421
  for (table= leaves; table; table= table->next_leaf)
unknown's avatar
unknown committed
8422
  {
unknown's avatar
unknown committed
8423 8424
    TABLE_LIST *embedded; /* The table at the current level of nesting. */
    TABLE_LIST *embedding= table; /* The parent nested table reference. */
8425
    do
unknown's avatar
VIEW  
unknown committed
8426
    {
8427 8428
      embedded= embedding;
      if (embedded->on_expr)
8429
      {
8430 8431
        /* Make a join an a expression */
        thd->where="on clause";
8432 8433
        if ((!embedded->on_expr->fixed &&
            embedded->on_expr->fix_fields(thd, &embedded->on_expr)) ||
8434
	    embedded->on_expr->check_cols(1))
8435
	  goto err_no_arena;
unknown's avatar
unknown committed
8436
        select_lex->cond_count++;
8437
      }
8438
      embedding= embedded->embedding;
unknown's avatar
unknown committed
8439
    }
8440 8441
    while (embedding &&
           embedding->nested_join->join_list.head() == embedded);
8442 8443 8444 8445

    /* process CHECK OPTION */
    if (it_is_update)
    {
unknown's avatar
unknown committed
8446
      TABLE_LIST *view= table->top_table();
8447 8448 8449 8450 8451 8452 8453
      if (view->effective_with_check)
      {
        if (view->prepare_check_option(thd))
          goto err_no_arena;
        thd->change_item_tree(&table->check_option, view->check_option);
      }
    }
unknown's avatar
unknown committed
8454
  }
unknown's avatar
unknown committed
8455

unknown's avatar
unknown committed
8456
  if (!thd->stmt_arena->is_conventional())
unknown's avatar
unknown committed
8457 8458 8459 8460 8461 8462 8463 8464 8465
  {
    /*
      We are in prepared statement preparation code => we should store
      WHERE clause changing for next executions.

      We do this ON -> WHERE transformation only once per PS/SP statement.
    */
    select_lex->where= *conds;
  }
8466
  thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
8467
  DBUG_RETURN(test(thd->is_error()));
unknown's avatar
unknown committed
8468

8469
err_no_arena:
8470
  select_lex->is_item_list_lookup= save_is_item_list_lookup;
unknown's avatar
unknown committed
8471
  DBUG_RETURN(1);
unknown's avatar
unknown committed
8472 8473 8474 8475 8476 8477 8478 8479
}


/******************************************************************************
** Fill a record with data (for INSERT or UPDATE)
** Returns : 1 if some field has wrong type
******************************************************************************/

unknown's avatar
unknown committed
8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490

/*
  Fill fields with given items.

  SYNOPSIS
    fill_record()
    thd           thread handler
    fields        Item_fields list to be filled
    values        values to fill with
    ignore_errors TRUE if we should ignore errors

8491 8492 8493 8494 8495
  NOTE
    fill_record() may set table->auto_increment_field_not_null and a
    caller should make sure that it is reset after their last call to this
    function.

unknown's avatar
unknown committed
8496 8497 8498 8499 8500
  RETURN
    FALSE   OK
    TRUE    error occured
*/

unknown's avatar
unknown committed
8501
static bool
unknown's avatar
unknown committed
8502 8503
fill_record(THD * thd, List<Item> &fields, List<Item> &values,
            bool ignore_errors)
unknown's avatar
unknown committed
8504
{
unknown's avatar
unknown committed
8505
  List_iterator_fast<Item> f(fields),v(values);
8506
  Item *value, *fld;
unknown's avatar
unknown committed
8507
  Item_field *field;
8508
  TABLE *table= 0;
unknown's avatar
unknown committed
8509 8510
  DBUG_ENTER("fill_record");

8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530
  /*
    Reset the table->auto_increment_field_not_null as it is valid for
    only one row.
  */
  if (fields.elements)
  {
    /*
      On INSERT or UPDATE fields are checked to be from the same table,
      thus we safely can take table from the first field.
    */
    fld= (Item_field*)f++;
    if (!(field= fld->filed_for_view_update()))
    {
      my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), fld->name);
      goto err;
    }
    table= field->field->table;
    table->auto_increment_field_not_null= FALSE;
    f.rewind();
  }
8531
  while ((fld= f++))
unknown's avatar
unknown committed
8532
  {
8533 8534 8535
    if (!(field= fld->filed_for_view_update()))
    {
      my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), fld->name);
8536
      goto err;
8537
    }
unknown's avatar
unknown committed
8538
    value=v++;
8539
    Field *rfield= field->field;
8540
    table= rfield->table;
unknown's avatar
unknown committed
8541
    if (rfield == table->next_number_field)
unknown's avatar
unknown committed
8542
      table->auto_increment_field_not_null= TRUE;
unknown's avatar
unknown committed
8543
    if ((value->save_in_field(rfield, 0) < 0) && !ignore_errors)
unknown's avatar
unknown committed
8544 8545
    {
      my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0));
8546
      goto err;
unknown's avatar
unknown committed
8547
    }
unknown's avatar
unknown committed
8548
  }
8549
  DBUG_RETURN(thd->is_error());
8550 8551 8552 8553
err:
  if (table)
    table->auto_increment_field_not_null= FALSE;
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
8554 8555 8556
}


unknown's avatar
unknown committed
8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586
/*
  Fill fields in list with values from the list of items and invoke
  before triggers.

  SYNOPSIS
    fill_record_n_invoke_before_triggers()
      thd           thread context
      fields        Item_fields list to be filled
      values        values to fill with
      ignore_errors TRUE if we should ignore errors
      triggers      object holding list of triggers to be invoked
      event         event type for triggers to be invoked

  NOTE
    This function assumes that fields which values will be set and triggers
    to be invoked belong to the same table, and that TABLE::record[0] and
    record[1] buffers correspond to new and old versions of row respectively.

  RETURN
    FALSE   OK
    TRUE    error occured
*/

bool
fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
                                     List<Item> &values, bool ignore_errors,
                                     Table_triggers_list *triggers,
                                     enum trg_event_type event)
{
  return (fill_record(thd, fields, values, ignore_errors) ||
8587 8588
          (triggers && triggers->process_triggers(thd, event,
                                                 TRG_ACTION_BEFORE, TRUE)));
unknown's avatar
unknown committed
8589 8590 8591
}


unknown's avatar
unknown committed
8592 8593 8594 8595 8596 8597 8598 8599 8600 8601
/*
  Fill field buffer with values from Field list

  SYNOPSIS
    fill_record()
    thd           thread handler
    ptr           pointer on pointer to record
    values        list of fields
    ignore_errors TRUE if we should ignore errors

8602 8603 8604 8605 8606
  NOTE
    fill_record() may set table->auto_increment_field_not_null and a
    caller should make sure that it is reset after their last call to this
    function.

unknown's avatar
unknown committed
8607 8608 8609 8610 8611 8612 8613
  RETURN
    FALSE   OK
    TRUE    error occured
*/

bool
fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors)
unknown's avatar
unknown committed
8614
{
unknown's avatar
unknown committed
8615
  List_iterator_fast<Item> v(values);
unknown's avatar
unknown committed
8616
  Item *value;
8617
  TABLE *table= 0;
unknown's avatar
unknown committed
8618 8619 8620
  DBUG_ENTER("fill_record");

  Field *field;
8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633
  /*
    Reset the table->auto_increment_field_not_null as it is valid for
    only one row.
  */
  if (*ptr)
  {
    /*
      On INSERT or UPDATE fields are checked to be from the same table,
      thus we safely can take table from the first field.
    */
    table= (*ptr)->table;
    table->auto_increment_field_not_null= FALSE;
  }
8634
  while ((field = *ptr++) && ! thd->is_error())
unknown's avatar
unknown committed
8635 8636
  {
    value=v++;
8637
    table= field->table;
unknown's avatar
unknown committed
8638
    if (field == table->next_number_field)
unknown's avatar
unknown committed
8639
      table->auto_increment_field_not_null= TRUE;
8640
    if (value->save_in_field(field, 0) < 0)
8641
      goto err;
unknown's avatar
unknown committed
8642
  }
8643
  DBUG_RETURN(thd->is_error());
8644 8645 8646 8647 8648

err:
  if (table)
    table->auto_increment_field_not_null= FALSE;
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
8649 8650 8651
}


unknown's avatar
unknown committed
8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679 8680 8681
/*
  Fill fields in array with values from the list of items and invoke
  before triggers.

  SYNOPSIS
    fill_record_n_invoke_before_triggers()
      thd           thread context
      ptr           NULL-ended array of fields to be filled
      values        values to fill with
      ignore_errors TRUE if we should ignore errors
      triggers      object holding list of triggers to be invoked
      event         event type for triggers to be invoked

  NOTE
    This function assumes that fields which values will be set and triggers
    to be invoked belong to the same table, and that TABLE::record[0] and
    record[1] buffers correspond to new and old versions of row respectively.

  RETURN
    FALSE   OK
    TRUE    error occured
*/

bool
fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
                                     List<Item> &values, bool ignore_errors,
                                     Table_triggers_list *triggers,
                                     enum trg_event_type event)
{
  return (fill_record(thd, ptr, values, ignore_errors) ||
8682 8683
          (triggers && triggers->process_triggers(thd, event,
                                                 TRG_ACTION_BEFORE, TRUE)));
unknown's avatar
unknown committed
8684 8685 8686
}


8687
my_bool mysql_rm_tmp_tables(void)
unknown's avatar
unknown committed
8688
{
unknown's avatar
unknown committed
8689
  uint i, idx;
8690
  char	filePath[FN_REFLEN], *tmpdir, filePathCopy[FN_REFLEN];
unknown's avatar
unknown committed
8691 8692
  MY_DIR *dirp;
  FILEINFO *file;
unknown's avatar
unknown committed
8693
  TABLE_SHARE share;
8694
  THD *thd;
unknown's avatar
unknown committed
8695 8696
  DBUG_ENTER("mysql_rm_tmp_tables");

8697 8698
  if (!(thd= new THD))
    DBUG_RETURN(1);
unknown's avatar
unknown committed
8699
  thd->thread_stack= (char*) &thd;
8700 8701
  thd->store_globals();

unknown's avatar
unknown committed
8702 8703 8704
  for (i=0; i<=mysql_tmpdir_list.max; i++)
  {
    tmpdir=mysql_tmpdir_list.list[i];
unknown's avatar
unknown committed
8705
    /* See if the directory exists */
unknown's avatar
unknown committed
8706 8707
    if (!(dirp = my_dir(tmpdir,MYF(MY_WME | MY_DONT_SORT))))
      continue;
unknown's avatar
unknown committed
8708

unknown's avatar
unknown committed
8709
    /* Remove all SQLxxx tables from directory */
unknown's avatar
unknown committed
8710

unknown's avatar
unknown committed
8711 8712 8713
    for (idx=0 ; idx < (uint) dirp->number_off_files ; idx++)
    {
      file=dirp->dir_entry+idx;
unknown's avatar
unknown committed
8714

unknown's avatar
unknown committed
8715 8716 8717 8718
      /* skiping . and .. */
      if (file->name[0] == '.' && (!file->name[1] ||
                                   (file->name[1] == '.' &&  !file->name[2])))
        continue;
unknown's avatar
unknown committed
8719

8720 8721
      if (!memcmp(file->name, tmp_file_prefix,
                  tmp_file_prefix_length))
unknown's avatar
unknown committed
8722
      {
unknown's avatar
unknown committed
8723 8724 8725 8726 8727
        char *ext= fn_ext(file->name);
        uint ext_len= strlen(ext);
        uint filePath_len= my_snprintf(filePath, sizeof(filePath),
                                       "%s%c%s", tmpdir, FN_LIBCHAR,
                                       file->name);
8728
        if (!memcmp(reg_ext, ext, ext_len))
8729
        {
unknown's avatar
unknown committed
8730 8731 8732 8733
          handler *handler_file= 0;
          /* We should cut file extention before deleting of table */
          memcpy(filePathCopy, filePath, filePath_len - ext_len);
          filePathCopy[filePath_len - ext_len]= 0;
8734
          init_tmp_table_share(thd, &share, "", 0, "", filePathCopy);
unknown's avatar
unknown committed
8735 8736
          if (!open_table_def(thd, &share, 0) &&
              ((handler_file= get_new_handler(&share, thd->mem_root,
unknown's avatar
unknown committed
8737
                                              share.db_type()))))
unknown's avatar
unknown committed
8738
          {
8739
            handler_file->ha_delete_table(filePathCopy);
unknown's avatar
unknown committed
8740 8741 8742
            delete handler_file;
          }
          free_table_share(&share);
8743
        }
unknown's avatar
unknown committed
8744 8745 8746 8747 8748
        /*
          File can be already deleted by tmp_table.file->delete_table().
          So we hide error messages which happnes during deleting of these
          files(MYF(0)).
        */
Marc Alff's avatar
Marc Alff committed
8749
        (void) mysql_file_delete(key_file_misc, filePath, MYF(0));
unknown's avatar
unknown committed
8750
      }
unknown's avatar
unknown committed
8751
    }
unknown's avatar
unknown committed
8752
    my_dirend(dirp);
unknown's avatar
unknown committed
8753
  }
8754 8755 8756
  delete thd;
  my_pthread_setspecific_ptr(THR_THD,  0);
  DBUG_RETURN(0);
unknown's avatar
unknown committed
8757 8758 8759 8760 8761 8762 8763 8764 8765
}



/*****************************************************************************
	unireg support functions
*****************************************************************************/

/*
unknown's avatar
unknown committed
8766 8767 8768 8769 8770
  free all unused tables

  NOTE
    This is called by 'handle_manager' when one wants to periodicly flush
    all not used tables.
unknown's avatar
unknown committed
8771 8772
*/

8773
void tdc_flush_unused_tables()
unknown's avatar
unknown committed
8774
{
Marc Alff's avatar
Marc Alff committed
8775
  mysql_mutex_lock(&LOCK_open);
unknown's avatar
unknown committed
8776
  while (unused_tables)
8777
    free_cache_entry(unused_tables);
8778
  mysql_mutex_unlock(&LOCK_open);
unknown's avatar
unknown committed
8779 8780 8781
}


8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798
/**
   A callback to the server internals that is used to address
   special cases of the locking protocol.
   Invoked when acquiring an exclusive lock, for each thread that
   has a conflicting shared metadata lock.

   This function:
     - aborts waiting of the thread on a data lock, to make it notice
       the pending exclusive lock and back off.
     - if the thread is an INSERT DELAYED thread, sends it a KILL
       signal to terminate it.

   @note This function does not wait for the thread to give away its
         locks. Waiting is done outside for all threads at once.

   @param thd    Current thread context
   @param in_use The thread to wake up
8799 8800 8801
   @param needs_thr_lock_abort Indicates that to wake up thread
                               this call needs to abort its waiting
                               on table-level lock.
8802 8803

   @retval  TRUE  if the thread was woken up
8804
   @retval  FALSE otherwise.
8805 8806 8807 8808 8809

   @note It is one of two places where border between MDL and the
         rest of the server is broken.
*/

8810 8811
bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
                                            bool needs_thr_lock_abort)
8812 8813 8814 8815 8816 8817
{
  bool signalled= FALSE;
  if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
      !in_use->killed)
  {
    in_use->killed= THD::KILL_CONNECTION;
8818
    mysql_mutex_lock(&in_use->mysys_var->mutex);
8819
    if (in_use->mysys_var->current_cond)
8820 8821
      mysql_cond_broadcast(in_use->mysys_var->current_cond);
    mysql_mutex_unlock(&in_use->mysys_var->mutex);
8822 8823
    signalled= TRUE;
  }
8824 8825

  if (needs_thr_lock_abort)
8826
  {
8827
    mysql_mutex_lock(&in_use->LOCK_thd_data);
8828 8829 8830 8831 8832 8833 8834 8835 8836 8837
    for (TABLE *thd_table= in_use->open_tables;
         thd_table ;
         thd_table= thd_table->next)
    {
      /*
        Check for TABLE::needs_reopen() is needed since in some places we call
        handler::close() for table instance (and set TABLE::db_stat to 0)
        and do not remove such instances from the THD::open_tables
        for some time, during which other thread can see those instances
        (e.g. see partitioning code).
8838
      */
8839 8840 8841
      if (!thd_table->needs_reopen())
        signalled|= mysql_lock_abort_for_thread(thd, thd_table);
    }
8842
    mysql_mutex_unlock(&in_use->LOCK_thd_data);
8843 8844 8845 8846 8847 8848
  }
  return signalled;
}


/**
Konstantin Osipov's avatar
Konstantin Osipov committed
8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871
   Remove all or some (depending on parameter) instances of TABLE and
   TABLE_SHARE from the table definition cache.

   @param  thd          Thread context
   @param  remove_type  Type of removal:
                        TDC_RT_REMOVE_ALL     - remove all TABLE instances and
                                                TABLE_SHARE instance. There
                                                should be no used TABLE objects
                                                and caller should have exclusive
                                                metadata lock on the table.
                        TDC_RT_REMOVE_NOT_OWN - remove all TABLE instances
                                                except those that belong to
                                                this thread. There should be
                                                no TABLE objects used by other
                                                threads and caller should have
                                                exclusive metadata lock on the
                                                table.
                        TDC_RT_REMOVE_UNUSED  - remove all unused TABLE
                                                instances (if there are no
                                                used instances will also
                                                remove TABLE_SHARE).
   @param  db           Name of database
   @param  table_name   Name of table
8872
   @param  has_lock     If TRUE, LOCK_open is already acquired
8873

8874 8875
   @note It assumes that table instances are already not used by any
   (other) thread (this should be achieved by using meta-data locks).
8876 8877
*/

Konstantin Osipov's avatar
Konstantin Osipov committed
8878
void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
8879 8880
                      const char *db, const char *table_name,
                      bool has_lock)
8881 8882 8883 8884 8885 8886
{
  char key[MAX_DBKEY_LENGTH];
  uint key_length;
  TABLE *table;
  TABLE_SHARE *share;

8887 8888 8889
  if (! has_lock)
    mysql_mutex_lock(&LOCK_open);
  else
8890
  {
8891
    mysql_mutex_assert_owner(&LOCK_open);
8892
  }
8893

Konstantin Osipov's avatar
Konstantin Osipov committed
8894
  DBUG_ASSERT(remove_type == TDC_RT_REMOVE_UNUSED ||
8895 8896
              thd->mdl_context.is_lock_owner(MDL_key::TABLE, db, table_name,
                                             MDL_EXCLUSIVE));
8897

Konstantin Osipov's avatar
Konstantin Osipov committed
8898
  key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
8899 8900 8901 8902

  if ((share= (TABLE_SHARE*) my_hash_search(&table_def_cache,(uchar*) key,
                                            key_length)))
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923
    if (share->ref_count)
    {
      I_P_List_iterator<TABLE, TABLE_share> it(share->free_tables);
#ifndef DBUG_OFF
      if (remove_type == TDC_RT_REMOVE_ALL)
      {
        DBUG_ASSERT(share->used_tables.is_empty());
      }
      else if (remove_type == TDC_RT_REMOVE_NOT_OWN)
      {
        I_P_List_iterator<TABLE, TABLE_share> it2(share->used_tables);
        while ((table= it2++))
          if (table->in_use != thd)
          {
            DBUG_ASSERT(0);
          }
      }
#endif
      /*
        Set share's version to zero in order to ensure that it gets
        automatically deleted once it is no longer referenced.
8924

8925
        Note that code in TABLE_SHARE::wait_for_old_version() assumes
8926 8927 8928 8929 8930
        that marking share as old and removal of its unused tables
        and of the share itself from TDC happens atomically under
        protection of LOCK_open, or, putting it another way, that
        TDC does not contain old shares which don't have any tables
        used.
Konstantin Osipov's avatar
Konstantin Osipov committed
8931 8932
      */
      share->version= 0;
8933

Konstantin Osipov's avatar
Konstantin Osipov committed
8934 8935 8936 8937 8938
      while ((table= it++))
        free_cache_entry(table);
    }
    else
      (void) my_hash_delete(&table_def_cache, (uchar*) share);
8939 8940
  }

8941 8942
  if (! has_lock)
    mysql_mutex_unlock(&LOCK_open);
8943 8944 8945
}


8946
int setup_ftfuncs(SELECT_LEX *select_lex)
unknown's avatar
unknown committed
8947
{
8948 8949
  List_iterator<Item_func_match> li(*(select_lex->ftfunc_list)),
                                 lj(*(select_lex->ftfunc_list));
8950
  Item_func_match *ftf, *ftf2;
unknown's avatar
unknown committed
8951 8952

  while ((ftf=li++))
8953
  {
unknown's avatar
unknown committed
8954 8955
    if (ftf->fix_index())
      return 1;
8956 8957
    lj.rewind();
    while ((ftf2=lj++) != ftf)
8958
    {
8959
      if (ftf->eq(ftf2,1) && !ftf2->master)
8960 8961 8962
        ftf2->master=ftf;
    }
  }
unknown's avatar
unknown committed
8963 8964 8965

  return 0;
}
8966

8967

8968
int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
8969
{
8970
  if (select_lex->ftfunc_list->elements)
8971
  {
8972
    List_iterator<Item_func_match> li(*(select_lex->ftfunc_list));
unknown's avatar
unknown committed
8973 8974
    Item_func_match *ifm;
    DBUG_PRINT("info",("Performing FULLTEXT search"));
8975
    thd_proc_info(thd, "FULLTEXT initialization");
8976

unknown's avatar
unknown committed
8977 8978 8979
    while ((ifm=li++))
      ifm->init_search(no_order);
  }
8980 8981
  return 0;
}
unknown's avatar
VIEW  
unknown committed
8982 8983 8984 8985 8986 8987 8988


/*
  open new .frm format table

  SYNOPSIS
    open_new_frm()
8989
    THD		  thread handler
unknown's avatar
unknown committed
8990
    path	  path to .frm file (without extension)
unknown's avatar
VIEW  
unknown committed
8991
    alias	  alias for table
8992 8993
    db            database
    table_name    name of table
8994
    db_stat	  open flags (for example ->OPEN_KEYFILE|HA_OPEN_RNDFILE..)
unknown's avatar
VIEW  
unknown committed
8995 8996 8997 8998 8999 9000 9001
		  can be 0 (example in ha_example_table)
    prgflag	  READ_ALL etc..
    ha_open_flags HA_OPEN_ABORT_IF_LOCKED etc..
    outparam	  result table
    table_desc	  TABLE_LIST descriptor
    mem_root	  temporary MEM_ROOT for parsing
*/
9002

Sergey Glukhov's avatar
Sergey Glukhov committed
9003
bool
unknown's avatar
unknown committed
9004
open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
9005
             uint db_stat, uint prgflag,
unknown's avatar
VIEW  
unknown committed
9006 9007 9008 9009
	     uint ha_open_flags, TABLE *outparam, TABLE_LIST *table_desc,
	     MEM_ROOT *mem_root)
{
  LEX_STRING pathstr;
9010
  File_parser *parser;
unknown's avatar
unknown committed
9011
  char path[FN_REFLEN];
9012 9013
  DBUG_ENTER("open_new_frm");

unknown's avatar
unknown committed
9014 9015 9016 9017
  /* Create path with extension */
  pathstr.length= (uint) (strxmov(path, share->normalized_path.str, reg_ext,
                                  NullS)- path);
  pathstr.str=    path;
9018

9019
  if ((parser= sql_parse_prepare(&pathstr, mem_root, 1)))
unknown's avatar
VIEW  
unknown committed
9020
  {
9021
    if (is_equal(&view_type, parser->type()))
unknown's avatar
VIEW  
unknown committed
9022
    {
9023
      if (table_desc == 0 || table_desc->required_type == FRMTYPE_TABLE)
unknown's avatar
VIEW  
unknown committed
9024
      {
unknown's avatar
unknown committed
9025 9026
        my_error(ER_WRONG_OBJECT, MYF(0), share->db.str, share->table_name.str,
                 "BASE TABLE");
9027
        goto err;
unknown's avatar
VIEW  
unknown committed
9028
      }
9029 9030
      if (mysql_make_view(thd, parser, table_desc,
                          (prgflag & OPEN_VIEW_NO_PARSE)))
9031
        goto err;
unknown's avatar
VIEW  
unknown committed
9032 9033 9034 9035
    }
    else
    {
      /* only VIEWs are supported now */
9036
      my_error(ER_FRM_UNKNOWN_TYPE, MYF(0), share->path.str,  parser->type()->str);
9037
      goto err;
unknown's avatar
VIEW  
unknown committed
9038
    }
9039
    DBUG_RETURN(0);
unknown's avatar
VIEW  
unknown committed
9040
  }
unknown's avatar
unknown committed
9041
 
9042 9043
err:
  DBUG_RETURN(1);
unknown's avatar
VIEW  
unknown committed
9044
}
9045 9046 9047 9048 9049 9050


bool is_equal(const LEX_STRING *a, const LEX_STRING *b)
{
  return a->length == b->length && !strncmp(a->str, b->str, a->length);
}
unknown's avatar
unknown committed
9051 9052 9053


/*
9054 9055
  Tells if two (or more) tables have auto_increment columns and we want to
  lock those tables with a write lock.
9056

9057 9058 9059
  SYNOPSIS
    has_two_write_locked_tables_with_auto_increment
      tables        Table list
unknown's avatar
unknown committed
9060 9061 9062 9063 9064 9065 9066 9067

  NOTES:
    Call this function only when you have established the list of all tables
    which you'll want to update (including stored functions, triggers, views
    inside your statement).
*/

static bool
9068
has_write_table_with_auto_increment(TABLE_LIST *tables)
unknown's avatar
unknown committed
9069 9070 9071 9072
{
  for (TABLE_LIST *table= tables; table; table= table->next_global)
  {
    /* we must do preliminary checks as table->table may be NULL */
unknown's avatar
unknown committed
9073
    if (!table->placeholder() &&
unknown's avatar
unknown committed
9074 9075
        table->table->found_next_number_field &&
        (table->lock_type >= TL_WRITE_ALLOW_WRITE))
9076
      return 1;
unknown's avatar
unknown committed
9077
  }
9078

unknown's avatar
unknown committed
9079 9080
  return 0;
}
9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108


/*
  Open and lock system tables for read.

  SYNOPSIS
    open_system_tables_for_read()
      thd         Thread context.
      table_list  List of tables to open.
      backup      Pointer to Open_tables_state instance where
                  information about currently open tables will be
                  saved, and from which will be restored when we will
                  end work with system tables.

  NOTES
    Thanks to restrictions which we put on opening and locking of
    system tables for writing, we can open and lock them for reading
    even when we already have some other tables open and locked.  One
    must call close_system_tables() to close systems tables opened
    with this call.

  RETURN
    FALSE   Success
    TRUE    Error
*/

bool
open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
9109
                            Open_tables_backup *backup)
9110
{
Konstantin Osipov's avatar
Konstantin Osipov committed
9111 9112 9113
  Query_tables_list query_tables_list_backup;
  LEX *lex= thd->lex;

9114 9115
  DBUG_ENTER("open_system_tables_for_read");

Konstantin Osipov's avatar
Konstantin Osipov committed
9116 9117 9118 9119 9120 9121 9122 9123
  /*
    Besides using new Open_tables_state for opening system tables,
    we also have to backup and reset/and then restore part of LEX
    which is accessed by open_tables() in order to determine if
    prelocking is needed and what tables should be added for it.
    close_system_tables() doesn't require such treatment.
  */
  lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
9124 9125
  thd->reset_n_backup_open_tables_state(backup);

9126
  if (open_and_lock_tables(thd, table_list, FALSE,
9127
                           MYSQL_OPEN_IGNORE_FLUSH |
9128
                           MYSQL_LOCK_IGNORE_TIMEOUT))
9129
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
9130
    lex->restore_backup_query_tables_list(&query_tables_list_backup);
9131 9132
    thd->restore_backup_open_tables_state(backup);
    DBUG_RETURN(TRUE);
9133 9134
  }

Konstantin Osipov's avatar
Konstantin Osipov committed
9135
  for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global)
9136
  {
Konstantin Osipov's avatar
Konstantin Osipov committed
9137 9138
    DBUG_ASSERT(tables->table->s->table_category == TABLE_CATEGORY_SYSTEM);
    tables->table->use_all_columns();
9139
  }
Konstantin Osipov's avatar
Konstantin Osipov committed
9140 9141 9142
  lex->restore_backup_query_tables_list(&query_tables_list_backup);

  DBUG_RETURN(FALSE);
9143 9144 9145 9146 9147 9148 9149 9150 9151
}


/*
  Close system tables, opened with open_system_tables_for_read().

  SYNOPSIS
    close_system_tables()
      thd     Thread context
9152
      backup  Pointer to Open_tables_backup instance which holds
9153 9154 9155 9156 9157
              information about tables which were open before we
              decided to access system tables.
*/

void
9158
close_system_tables(THD *thd, Open_tables_backup *backup)
9159 9160 9161 9162 9163 9164
{
  close_thread_tables(thd);
  thd->restore_backup_open_tables_state(backup);
}


9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196
/**
  A helper function to close a mysql.* table opened
  in an auxiliary THD during bootstrap or in the main
  connection, when we know that there are no locks
  held by the connection due to a preceding implicit
  commit.

  This function assumes that there is no
  statement transaction started for the operation
  itself, since mysql.* tables are not transactional
  and when they are used the binlog is off (DDL
  binlogging is always statement-based.

  We need this function since we'd like to not
  just close the system table, but also release
  the metadata lock on it.

  Note, that in LOCK TABLES mode this function
  does not release the metadata lock. But in this
  mode the table can be opened only if it is locked
  explicitly with LOCK TABLES.
*/

void
close_mysql_tables(THD *thd)
{
  /* No need to commit/rollback statement transaction, it's not started. */
  DBUG_ASSERT(thd->transaction.stmt.is_empty());
  close_thread_tables(thd);
  thd->mdl_context.release_transactional_locks();
}

9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217
/*
  Open and lock one system table for update.

  SYNOPSIS
    open_system_table_for_update()
      thd        Thread context.
      one_table  Table to open.

  NOTES
    Table opened with this call should closed using close_thread_tables().

  RETURN
    0	Error
    #	Pointer to TABLE object of system table
*/

TABLE *
open_system_table_for_update(THD *thd, TABLE_LIST *one_table)
{
  DBUG_ENTER("open_system_table_for_update");

9218 9219
  TABLE *table= open_ltable(thd, one_table, one_table->lock_type,
                            MYSQL_LOCK_IGNORE_TIMEOUT);
9220 9221
  if (table)
  {
9222
    DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_SYSTEM);
9223 9224 9225 9226 9227
    table->use_all_columns();
  }

  DBUG_RETURN(table);
}
9228 9229

/**
Marc Alff's avatar
Marc Alff committed
9230
  Open a log table.
9231 9232 9233 9234
  Opening such tables is performed internally in the server
  implementation, and is a 'nested' open, since some tables
  might be already opened by the current thread.
  The thread context before this call is saved, and is restored
Marc Alff's avatar
Marc Alff committed
9235
  when calling close_log_table().
9236
  @param thd The current thread
Marc Alff's avatar
Marc Alff committed
9237
  @param one_table Log table to open
9238 9239 9240
  @param backup [out] Temporary storage used to save the thread context
*/
TABLE *
9241
open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup)
9242
{
9243
  uint flags= ( MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |
9244
                MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |
9245
                MYSQL_OPEN_IGNORE_FLUSH |
9246
                MYSQL_LOCK_IGNORE_TIMEOUT |
9247
                MYSQL_LOCK_LOG_TABLE);
9248 9249 9250
  TABLE *table;
  /* Save value that is changed in mysql_lock_tables() */
  ulonglong save_utime_after_lock= thd->utime_after_lock;
Marc Alff's avatar
Marc Alff committed
9251
  DBUG_ENTER("open_log_table");
9252 9253 9254

  thd->reset_n_backup_open_tables_state(backup);

9255
  if ((table= open_ltable(thd, one_table, one_table->lock_type, flags)))
9256
  {
Marc Alff's avatar
Marc Alff committed
9257
    DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_LOG);
9258
    /* Make sure all columns get assigned to a default value */
9259
    table->use_all_columns();
9260
    table->no_replicate= 1;
9261 9262 9263 9264 9265
    /*
      Don't set automatic timestamps as we may want to use time of logging,
      not from query start
    */
    table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
9266
  }
9267 9268
  else
    thd->restore_backup_open_tables_state(backup);
9269

9270
  thd->utime_after_lock= save_utime_after_lock;
9271 9272
  DBUG_RETURN(table);
}
9273 9274

/**
Marc Alff's avatar
Marc Alff committed
9275 9276
  Close a log table.
  The last table opened by open_log_table()
9277 9278 9279 9280
  is closed, then the thread context is restored.
  @param thd The current thread
  @param backup [in] the context to restore.
*/
9281
void close_log_table(THD *thd, Open_tables_backup *backup)
9282
{
9283
  close_system_tables(thd, backup);
9284 9285
}

9286 9287 9288
/**
  @} (end of group Data_Dictionary)
*/