open_table

/*
  Open a table.

  SYNOPSIS
    open_table()
    thd                 Thread context.
    table_list          Open first table in list.
    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.
    flags               Bitmap of flags to modify how open works:
                          MYSQL_OPEN_IGNORE_FLUSH - Open table even if
                          someone has done a flush or there is a pending
                          exclusive metadata lock requests against it
                          (i.e. request high priority metadata lock).
                          No version number checking is done.
                          MYSQL_OPEN_TEMPORARY_ONLY - Open only temporary
                          table not the base table or view.
                          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.

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

    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.

  RETURN
    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).
*/

bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
                Open_table_context *ot_ctx)
{
  reg1    TABLE *table;
  char    key[MAX_DBKEY_LENGTH];
  uint    key_length;
  char    *alias= table_list->alias;
  uint flags= ot_ctx->get_flags();
  MDL_ticket *mdl_ticket;
  int error;
  TABLE_SHARE *share;
  my_hash_value_type hash_value;
  DBUG_ENTER("open_table");

  /* an open table operation needs a lot of the stack space */
  if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (uchar *)&alias))
    DBUG_RETURN(TRUE);

  if (thd->killed)
    DBUG_RETURN(TRUE);

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

  /*
    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.
  */
  if (table_list->open_type != OT_BASE_ONLY &&
      ! (flags & MYSQL_OPEN_SKIP_TEMPORARY))
  {
    for (table= thd->temporary_tables; table ; table=table->next)
    {
      if (table->s->table_cache_key.length == key_length +
          TMP_TABLE_KEY_EXTRA &&
      !memcmp(table->s->table_cache_key.str, key,
          key_length + TMP_TABLE_KEY_EXTRA))
      {
        /*
          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.
        */
    if (table->query_id)
    {
          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));
      my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
      DBUG_RETURN(TRUE);
    }
    table->query_id= thd->query_id;
    thd->thread_specific_used= TRUE;
        DBUG_PRINT("info",("Using temporary table"));
        goto reset;
      }
    }
  }

  if (table_list->open_type == OT_TEMPORARY_ONLY ||
      (flags & MYSQL_OPEN_TEMPORARY_ONLY))
  {
    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);
  }

  /*
    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.
  */
  if (thd->locked_tables_mode &&
      ! (flags & MYSQL_OPEN_GET_NEW_TABLE))
  {                        // Using table locks
    TABLE *best_table= 0;
    int best_distance= INT_MIN;
    for (table=thd->open_tables; table ; table=table->next)
    {
      if (table->s->table_cache_key.length == key_length &&
      !memcmp(table->s->table_cache_key.str, key, key_length))
      {
        if (!my_strcasecmp(system_charset_info, table->alias, alias) &&
            table->query_id != thd->query_id && /* skip tables already used */
            (thd->locked_tables_mode == LTM_LOCK_TABLES ||
             table->query_id == 0))
        {
          int distance= ((int) table->reginfo.lock_type -
                         (int) table_list->lock_type);

          /*
            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
          */
          if ((best_distance < 0 && distance > best_distance) ||
              (distance >= 0 && distance < best_distance))
          {
            best_distance= distance;
            best_table= table;
            if (best_distance == 0)
            {
              /*
                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().
              */
              break;
            }
          }
        }
      }
    }
    if (best_table)
    {
      table= best_table;
      table->query_id= thd->query_id;
      DBUG_PRINT("info",("Using locked table"));
      goto reset;
    }
    /*
      Is this table a view and not a base table?
      (it is work around to allow to open view with locked tables,
      real fix will be made after definition cache will be made)

      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.
    */
    if (thd->mdl_context.is_lock_owner(MDL_key::TABLE,
                                       table_list->db,
                                       table_list->table_name,
                                       MDL_SHARED))
    {
      char path[FN_REFLEN + 1];
      enum legacy_db_type not_used;
      build_table_filename(path, sizeof(path) - 1,
                           table_list->db, table_list->table_name, reg_ext, 0);
      /*
        Note that we can‘t be 100% sure that it is a view since it‘s
        possible that we either simply have not found unused TABLE
        instance in THD::open_tables list or were unable to open table
        during prelocking process (in this case in theory we still
        should hold shared metadata lock on it).
      */
      if (dd_frm_type(thd, path, &not_used) == FRMTYPE_VIEW)
      {
        if (!tdc_open_view(thd, table_list, alias, key, key_length,
                           mem_root, 0))
        {
          DBUG_ASSERT(table_list->view != 0);
          DBUG_RETURN(FALSE); // VIEW
        }
      }
    }
    /*
      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.
    */
    if (thd->locked_tables_mode == LTM_PRELOCKED)
      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);
  }

  /*
    Non pre-locked/LOCK TABLES mode, and the table is not temporary.
    This is the normal use case.
  */

  if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK))
  {
    /*
      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();
    }

    if (open_table_get_mdl_lock(thd, ot_ctx, &table_list->mdl_request,
                                flags, &mdl_ticket) ||
        mdl_ticket == NULL)
    {
      DEBUG_SYNC(thd, "before_open_table_wait_refresh");
      DBUG_RETURN(TRUE);
    }
    DEBUG_SYNC(thd, "after_open_table_mdl_shared");
  }
  else
  {
    /*
      Grab reference to the MDL lock ticket that was acquired
      by the caller.
    */
    mdl_ticket= table_list->mdl_request.ticket;
  }

  hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);

  if (table_list->open_strategy == TABLE_LIST::OPEN_IF_EXISTS)
  {
    bool exists;

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

    if (!exists)
      DBUG_RETURN(FALSE);

    /* Table exists. Let us try to open it. */
  }
  else if (table_list->open_strategy == TABLE_LIST::OPEN_STUB)
    DBUG_RETURN(FALSE);

retry_share:

  mysql_mutex_lock(&LOCK_open);

  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);
  }

  if (share->is_view)
  {
    /*
      If parent_l of the table_list is non null then a merge table
      has this view as child table, which is not supported.
    */
    if (table_list->parent_l)
    {
      my_error(ER_WRONG_MRG_TABLE, MYF(0));
      goto err_unlock;
    }

    /*
      This table is a view. Validate its metadata version: in particular,
      that it was a view when the statement was prepared.
    */
    if (check_and_update_table_version(thd, table_list, share))
      goto err_unlock;
    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);
      goto err_unlock;
    }

    /* 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);
  }

  /*
    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)
  {
    my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db,
             table_list->table_name);
    goto err_unlock;
  }

  if (!(flags & MYSQL_OPEN_IGNORE_FLUSH))
  {
    if (share->has_old_version())
    {
      /*
        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);
      mysql_mutex_unlock(&LOCK_open);

      thd->push_internal_handler(&mdl_deadlock_handler);
      wait_result= tdc_wait_for_old_version(thd, table_list->db,
                                            table_list->table_name,
                                            ot_ctx->get_timeout(),
                                            mdl_ticket->get_deadlock_weight());
      thd->pop_internal_handler();

      if (wait_result)
        DBUG_RETURN(TRUE);

      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.
      */
      release_table_share(share);
      mysql_mutex_unlock(&LOCK_open);
      (void)ot_ctx->request_backoff_action(Open_table_context::OT_REOPEN_TABLES,
                                           NULL);
      DBUG_RETURN(TRUE);
    }
  }

  if (!share->free_tables.is_empty())
  {
    table= share->free_tables.front();
    table_def_use_table(thd, table);
    /* We need to release share as we have EXTRA reference to it in our hands. */
    release_table_share(share);
  }
  else
  {
    /* 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);

    mysql_mutex_unlock(&LOCK_open);

    /* make a new table */
    if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME))))
      goto err_lock;

    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);

    if (error)
    {
      my_free(table);

      if (error == 7)
        (void) ot_ctx->request_backoff_action(Open_table_context::OT_DISCOVER,
                                              table_list);
      else if (share->crashed)
        (void) ot_ctx->request_backoff_action(Open_table_context::OT_REPAIR,
                                              table_list);

      goto err_lock;
    }

    if (open_table_entry_fini(thd, share, table))
    {
      closefrm(table, 0);
      my_free(table);
      goto err_lock;
    }

    mysql_mutex_lock(&LOCK_open);
    /* Add table to the share‘s used tables list. */
    table_def_add_used_table(thd, table);
  }

  mysql_mutex_unlock(&LOCK_open);

  table->mdl_ticket= mdl_ticket;

  table->next= thd->open_tables;        /* Link into simple list */
  thd->set_open_tables(table);

  table->reginfo.lock_type=TL_READ;        /* Assume read */

 reset:
  /*
    Check that there is no reference to a condtion from an earlier query
    (cf. Bug#58553).
  */
  DBUG_ASSERT(table->file->pushed_cond == NULL);
  table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
  table_list->table= table;

  table->init(thd, table_list);

  DBUG_RETURN(FALSE);

err_lock:
  mysql_mutex_lock(&LOCK_open);
err_unlock:
  release_table_share(share);
  mysql_mutex_unlock(&LOCK_open);

  DBUG_RETURN(TRUE);
}
/*
  Open a table based on a TABLE_SHARE

  SYNOPSIS
    open_table_from_share()
    thd            Thread handler
    share        Table definition
    alias           Alias for table
    db_stat        open flags (for example HA_OPEN_KEYFILE|
                HA_OPEN_RNDFILE..) can be 0 (example in
                        ha_example_table)
    prgflag           READ_ALL etc..
    ha_open_flags    HA_OPEN_ABORT_IF_LOCKED etc..
    outparam           result table

  RETURN VALUES
   0    ok
   1    Error (see open_table_error)
   2    Error (see open_table_error)
   3    Wrong data in .frm file
   4    Error (see open_table_error)
   5    Error (see open_table_error: charset unavailable)
   7    Table definition has changed in engine
*/

int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias,
                          uint db_stat, uint prgflag, uint ha_open_flags,
                          TABLE *outparam, bool is_create_table)
{
  int error;
  uint records, i, bitmap_size;
  bool error_reported= FALSE;
  uchar *record, *bitmaps;
  Field **field_ptr;
  DBUG_ENTER("open_table_from_share");
  DBUG_PRINT("enter",("name: ‘%s.%s‘  form: 0x%lx", share->db.str,
                      share->table_name.str, (long) outparam));

  error= 1;
  bzero((char*) outparam, sizeof(*outparam));
  outparam->in_use= thd;
  outparam->s= share;
  outparam->db_stat= db_stat;
  outparam->write_row_record= NULL;

  init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);

  if (!(outparam->alias= my_strdup(alias, MYF(MY_WME))))
    goto err;
  outparam->quick_keys.init();
  outparam->covering_keys.init();
  outparam->merge_keys.init();
  outparam->keys_in_use_for_query.init();

  /* Allocate handler */
  outparam->file= 0;
  if (!(prgflag & OPEN_FRM_FILE_ONLY))
  {
    if (!(outparam->file= get_new_handler(share, &outparam->mem_root,
                                          share->db_type())))
      goto err;
  }
  else
  {
    DBUG_ASSERT(!db_stat);
  }

  error= 4;
  outparam->reginfo.lock_type= TL_UNLOCK;
  outparam->current_lock= F_UNLCK;
  records=0;
  if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN))
    records=1;
  if (prgflag & (READ_ALL+EXTRA_RECORD))
    records++;

  if (!(record= (uchar*) alloc_root(&outparam->mem_root,
                                   share->rec_buff_length * records)))
    goto err;                                   /* purecov: inspected */

  if (records == 0)
  {
    /* We are probably in hard repair, and the buffers should not be used */
    outparam->record[0]= outparam->record[1]= share->default_values;
  }
  else
  {
    outparam->record[0]= record;
    if (records > 1)
      outparam->record[1]= record+ share->rec_buff_length;
    else
      outparam->record[1]= outparam->record[0];   // Safety
  }

#ifdef HAVE_purify
  /*
    We need this because when we read var-length rows, we are not updating
    bytes after end of varchar
  */
  if (records > 1)
  {
    memcpy(outparam->record[0], share->default_values, share->rec_buff_length);
    memcpy(outparam->record[1], share->default_values, share->null_bytes);
    if (records > 2)
      memcpy(outparam->record[1], share->default_values,
             share->rec_buff_length);
  }
#endif

  if (!(field_ptr = (Field **) alloc_root(&outparam->mem_root,
                                          (uint) ((share->fields+1)*
                                                  sizeof(Field*)))))
    goto err;                                   /* purecov: inspected */

  outparam->field= field_ptr;

  record= (uchar*) outparam->record[0]-1;    /* Fieldstart = 1 */
  if (share->null_field_first)
    outparam->null_flags= (uchar*) record+1;
  else
    outparam->null_flags= (uchar*) (record+ 1+ share->reclength -
                                    share->null_bytes);

  /* Setup copy of fields from share, but use the right alias and record */
  for (i=0 ; i < share->fields; i++, field_ptr++)
  {
    if (!((*field_ptr)= share->field[i]->clone(&outparam->mem_root, outparam)))
      goto err;
  }
  (*field_ptr)= 0;                              // End marker

  if (share->found_next_number_field)
    outparam->found_next_number_field=
      outparam->field[(uint) (share->found_next_number_field - share->field)];
  if (share->timestamp_field)
    outparam->timestamp_field= (Field_timestamp*) outparam->field[share->timestamp_field_offset];

  /* Fix key->name and key_part->field */
  if (share->key_parts)
  {
    KEY    *key_info, *key_info_end;
    KEY_PART_INFO *key_part;
    uint n_length;
    n_length= share->keys*sizeof(KEY) + share->key_parts*sizeof(KEY_PART_INFO);
    if (!(key_info= (KEY*) alloc_root(&outparam->mem_root, n_length)))
      goto err;
    outparam->key_info= key_info;
    key_part= (reinterpret_cast<KEY_PART_INFO*>(key_info+share->keys));

    memcpy(key_info, share->key_info, sizeof(*key_info)*share->keys);
    memcpy(key_part, share->key_info[0].key_part, (sizeof(*key_part) *
                                                   share->key_parts));

    for (key_info_end= key_info + share->keys ;
         key_info < key_info_end ;
         key_info++)
    {
      KEY_PART_INFO *key_part_end;

      key_info->table= outparam;
      key_info->key_part= key_part;

      for (key_part_end= key_part+ key_info->key_parts ;
           key_part < key_part_end ;
           key_part++)
      {
        Field *field= key_part->field= outparam->field[key_part->fieldnr-1];

        if (field->key_length() != key_part->length &&
            !(field->flags & BLOB_FLAG))
        {
          /*
            We are using only a prefix of the column as a key:
            Create a new field for the key part that matches the index
          */
          field= key_part->field=field->new_field(&outparam->mem_root,
                                                  outparam, 0);
          field->field_length= key_part->length;
        }
      }
    }
  }

#ifdef WITH_PARTITION_STORAGE_ENGINE
  if (share->partition_info_str_len && outparam->file)
  {
  /*
    In this execution we must avoid calling thd->change_item_tree since
    we might release memory before statement is completed. We do this
    by changing to a new statement arena. As part of this arena we also
    set the memory root to be the memory root of the table since we
    call the parser and fix_fields which both can allocate memory for
    item objects. We keep the arena to ensure that we can release the
    free_list when closing the table object.
    SEE Bug #21658
  */

    Query_arena *backup_stmt_arena_ptr= thd->stmt_arena;
    Query_arena backup_arena;
    Query_arena part_func_arena(&outparam->mem_root,
                                Query_arena::STMT_INITIALIZED);
    thd->set_n_backup_active_arena(&part_func_arena, &backup_arena);
    thd->stmt_arena= &part_func_arena;
    bool tmp;
    bool work_part_info_used;

    tmp= mysql_unpack_partition(thd, share->partition_info_str,
                                share->partition_info_str_len,
                                outparam, is_create_table,
                                share->default_part_db_type,
                                &work_part_info_used);
    if (tmp)
    {
      thd->stmt_arena= backup_stmt_arena_ptr;
      thd->restore_active_arena(&part_func_arena, &backup_arena);
      goto partititon_err;
    }
    outparam->part_info->is_auto_partitioned= share->auto_partitioned;
    DBUG_PRINT("info", ("autopartitioned: %u", share->auto_partitioned));
    /* we should perform the fix_partition_func in either local or
       caller‘s arena depending on work_part_info_used value
    */
    if (!work_part_info_used)
      tmp= fix_partition_func(thd, outparam, is_create_table);
    thd->stmt_arena= backup_stmt_arena_ptr;
    thd->restore_active_arena(&part_func_arena, &backup_arena);
    if (!tmp)
    {
      if (work_part_info_used)
        tmp= fix_partition_func(thd, outparam, is_create_table);
    }
    outparam->part_info->item_free_list= part_func_arena.free_list;
partititon_err:
    if (tmp)
    {
      if (is_create_table)
      {
        /*
          During CREATE/ALTER TABLE it is ok to receive errors here.
          It is not ok if it happens during the opening of an frm
          file as part of a normal query.
        */
        error_reported= TRUE;
      }
      goto err;
    }
  }
#endif

  /* Allocate bitmaps */

  bitmap_size= share->column_bitmap_size;
  if (!(bitmaps= (uchar*) alloc_root(&outparam->mem_root, bitmap_size*3)))
    goto err;
  bitmap_init(&outparam->def_read_set,
              (my_bitmap_map*) bitmaps, share->fields, FALSE);
  bitmap_init(&outparam->def_write_set,
              (my_bitmap_map*) (bitmaps+bitmap_size), share->fields, FALSE);
  bitmap_init(&outparam->tmp_set,
              (my_bitmap_map*) (bitmaps+bitmap_size*2), share->fields, FALSE);
  outparam->default_column_bitmaps();

  /* The table struct is now initialized;  Open the table */
  error= 2;
  if (db_stat)
  {
    int ha_err;
    if ((ha_err= (outparam->file->
                  ha_open(outparam, share->normalized_path.str,
                          (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
                          (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
                           ((db_stat & HA_WAIT_IF_LOCKED) ||
                            (specialflag & SPECIAL_WAIT_IF_LOCKED)) ?
                           HA_OPEN_WAIT_IF_LOCKED :
                           (db_stat & (HA_ABORT_IF_LOCKED | HA_GET_INFO)) ?
                          HA_OPEN_ABORT_IF_LOCKED :
                           HA_OPEN_IGNORE_IF_LOCKED) | ha_open_flags))))
    {
      /* Set a flag if the table is crashed and it can be auto. repaired */
      share->crashed= ((ha_err == HA_ERR_CRASHED_ON_USAGE) &&
                       outparam->file->auto_repair() &&
                       !(ha_open_flags & HA_OPEN_FOR_REPAIR));

      switch (ha_err)
      {
        case HA_ERR_NO_SUCH_TABLE:
      /*
            The table did not exists in storage engine, use same error message
            as if the .frm file didn‘t exist
          */
      error= 1;
      my_errno= ENOENT;
          break;
        case EMFILE:
      /*
            Too many files opened, use same error message as if the .frm
            file can‘t open
           */
          DBUG_PRINT("error", ("open file: %s failed, too many files opened (errno: %d)",
          share->normalized_path.str, ha_err));
      error= 1;
      my_errno= EMFILE;
          break;
        default:
          outparam->file->print_error(ha_err, MYF(0));
          error_reported= TRUE;
          if (ha_err == HA_ERR_TABLE_DEF_CHANGED)
            error= 7;
          break;
      }
      goto err;                                 /* purecov: inspected */
    }
  }

#if defined(HAVE_purify) && !defined(DBUG_OFF)
  bzero((char*) bitmaps, bitmap_size*3);
#endif

  outparam->no_replicate= outparam->file &&
                          test(outparam->file->ha_table_flags() &
                               HA_HAS_OWN_BINLOGGING);
  /* Increment the opened_tables counter, only when open flags set. */
  if (db_stat)
    thd->status_var.opened_tables++;

  DBUG_RETURN (0);

 err:
  if (! error_reported)
    open_table_error(share, error, my_errno, 0);
  delete outparam->file;
#ifdef WITH_PARTITION_STORAGE_ENGINE
  if (outparam->part_info)
    free_items(outparam->part_info->item_free_list);
#endif
  outparam->file= 0;                // For easier error checking
  outparam->db_stat=0;
  free_root(&outparam->mem_root, MYF(0));       // Safe to call on bzero‘d root
  my_free((void *) outparam->alias);
  DBUG_RETURN (error);
}
时间: 2024-11-05 12:31:43

open_table的相关文章

MySQL备份锁

无论逻辑备份还是物理备份,为了获取一致性位点,都强依赖于FTWRL(Flush Table With Read Lock).这个锁杀伤力非常大,因为持有锁的这段时间,整个数据库实质上不能对外提供写服务的.此外,由于FTWRL需要关闭表,如有大查询,会导致FTWRL等待,进而导致DML堵塞的时间变长.即使是备库,也有SQL线程在复制来源于主库的更新,上全局锁时,会导致主备库延迟.FTWRL这把锁持有的时间主要与非innodb表的数据量有关,如果非innodb表数据量很大,备份很慢,那么持有锁的时间

MySQL连接查询流程源码分析

初始化 main |-mysqld |-my_init // 初始话线程变量,互斥量 |-load_defaults // 获取配置 |-init_common_variables // 初始化变量 |-init_server_components // 初始化插件 | |-plugin_init | | |-plugin_initialize | |-initialize_storage_engine |-network_init // 监听网络 |-grant_init |-servers_

【转】A* A星 算法 C语言 实现代码

http://blog.csdn.net/shanshanpt/article/details/8977512 关于A*算法,很早就想写点什么,可是貌似天天在忙活着什么,可事实又没有做什么,真是浮躁啊!所以今晚还是来写一下总结吧! A*算法是很经典的只能启发式搜索算法,关于只能搜索算法和一般的搜索算法(例如DFS,BFS之类),在语言描述上的区别,我觉得用<代码大全>中的一句话描述的非常好:“驾驶汽车达到某人家,写成算法是:沿167号高速往南行至Puyallup,从XX出口后往山上开4.5英里

MySQL锁系列2 表锁

上一篇介绍了MySQL源码中保护内存结构或变量的锁,这里开始介绍下MySQL事务中的表锁. 注1: 在表锁的实现上面,使用[mutex+condition+queue]的结构实现并发,阻塞,唤醒的表锁功能. 注2: 本文进行的一些实验,重要的配置项: 1. autocommit=0 2. tx_isolation=read-commited 3. engine=innodb 1. MySQL加锁的顺序: 这里包括了一个sql在执行的过程中,包括commit,所添加和释放跟事务相关的锁以及加不同锁

自动化上传数据(三)

excel处理类和上传类都已经写好,分别保存在excelHandle.py和upload.py中,最后我们需要写一个run.py去执行上传脚本. #!/usr/bin/python # -*- coding: utf-8 -*- import excelHandle import upload import Queue import time def run(filepath, username, password, url): 首先引入excelHandle,upload文件,time包,以及

information_schema Introduction

information_schema介绍 information_schema数据库是MySQL自带的,里面的“表”保存着服务器当前的实时信息.它提供了访问数据库元数据的方式.元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等.有些时候用于表述该信息的其他术语包括“数据词典”和“系统目录”.在MySQL中,把information_schema 看作是一个数据库,确切说是信息数据库.其中保存着关于MySQL服务器所维护的所有其他数据库的信息.如数据库名,数据库的表,表栏的数据类

MySQL锁系列3 MDL锁

MySQL为了保护数据字典元数据,使用了metadata lock,即MDL锁,保证在并发的情况下,结构变更的一致性. MDL锁的加锁模式和源码上的组织上和上一篇blog中MySQL表锁的实现方式一致,都采用了[mutex+condition+queue]来实现并发,阻塞,唤醒的控制. 下面就来看看MDL锁: 1. 重要的数据结构:    1. MDL_map mdl_map使用hash表,保存了MySQL所有的mdl_lock,全局共享,使用MDL_KEY作为key来表,key=[db_nam

MySQL open table

MySQL open table 背景:    MySQL经常会遇到Too many open files,MySQL上的open_files_limit和OS层面上设置的open file limit有什么关系? 源码中也会看到不同的数据结构,TABLE, TABLE_SHARE,跟表是什么关系?MySQL flush tables又做了些什么,这几个东西放在一起,就会比较迷惑,下面进行梳理一下: 1 数据结构 table: MySQL为每一个查询sql中的表建一个TABLE对象table_s

Mysql性能优化(二)--MySQL监控

1.检查监控服务是否正常提供: 命令: mysqladmin -uroot -p密码 -h服务器主机地址 ping 正常应该显示:mysqld is alive 2.获取mysql当前的状态值 mysqladmin -uroot -p密码 -h服务器主机地址 status uptime:服务器启动后的运行时间 Questions: SQL查询数 Threads: 当前连接数 Slow queries:慢查询数 Opens:已经打开的表的数量 Open_table 表示打开过的表数量 Querie