TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
					     Table_ident *table,
					     LEX_CSTRING *alias,
					     ulong table_options,
					     thr_lock_type lock_type,
					     enum_mdl_type mdl_type,
					     List<Index_hint> *index_hints_arg,
                                             List<String> *partition_names,
                                             LEX_STRING *option)
{
  TABLE_LIST *ptr;
  TABLE_LIST *UNINIT_VAR(previous_table_ref); /* The table preceding the current one. */
  LEX_CSTRING alias_str;
  LEX *lex= thd->lex;
  DBUG_ENTER("add_table_to_list");
  DBUG_PRINT("enter", ("Table '%s' (%p)  Select %p (%u)",
                        (alias ? alias->str : table->table.str),
                        table,
                        this, select_number));
  DBUG_ASSERT(!is_service_select  || (table_options & TL_OPTION_SEQUENCE));

  if (unlikely(!table))
    DBUG_RETURN(0);				// End of memory
  alias_str= alias ? *alias : table->table;
  DBUG_ASSERT(alias_str.str);
  if (!MY_TEST(table_options & TL_OPTION_ALIAS) &&
      unlikely(check_table_name(table->table.str, table->table.length, FALSE)))
  {
    my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
    DBUG_RETURN(0);
  }

  if (unlikely(table->is_derived_table() == FALSE && table->db.str &&
               check_db_name((LEX_STRING*) &table->db)))
  {
    my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str);
    DBUG_RETURN(0);
  }

  if (!alias)                            /* Alias is case sensitive */
  {
    if (unlikely(table->sel))
    {
      my_message(ER_DERIVED_MUST_HAVE_ALIAS,
                 ER_THD(thd, ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
      DBUG_RETURN(0);
    }
    /* alias_str points to table->table;  Let's make a copy */
    if (unlikely(!(alias_str.str= (char*) thd->memdup(alias_str.str, alias_str.length+1))))
      DBUG_RETURN(0);
  }
  if (unlikely(!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST)))))
    DBUG_RETURN(0);				/* purecov: inspected */
  if (table->db.str)
  {
    ptr->is_fqtn= TRUE;
    ptr->db= table->db;
  }
  else if (!lex->with_cte_resolution && lex->copy_db_to(&ptr->db))
    DBUG_RETURN(0);
  else
    ptr->is_fqtn= FALSE;

  ptr->alias= alias_str;
  ptr->is_alias= alias ? TRUE : FALSE;
  if (lower_case_table_names)
  {
    if (table->table.length)
      table->table.length= my_casedn_str(files_charset_info,
                                         (char*) table->table.str);
    if (ptr->db.length && ptr->db.str != any_db)
      ptr->db.length= my_casedn_str(files_charset_info, (char*) ptr->db.str);
  }

  ptr->table_name= table->table;
  ptr->lock_type= lock_type;
  ptr->mdl_type= mdl_type;
  ptr->table_options= table_options;
  ptr->updating=    MY_TEST(table_options & TL_OPTION_UPDATING);
  /* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */
  ptr->force_index= MY_TEST(table_options & TL_OPTION_FORCE_INDEX);
  ptr->ignore_leaves= MY_TEST(table_options & TL_OPTION_IGNORE_LEAVES);
  ptr->sequence=      MY_TEST(table_options & TL_OPTION_SEQUENCE);
  ptr->derived=	    table->sel;
  if (!ptr->derived && is_infoschema_db(&ptr->db))
  {
    if (ptr->updating &&
        /* Special cases which are processed by commands itself */
        lex->sql_command != SQLCOM_CHECK &&
        lex->sql_command != SQLCOM_CHECKSUM)
    {
      my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
               thd->security_ctx->priv_user,
               thd->security_ctx->priv_host,
               INFORMATION_SCHEMA_NAME.str);
      DBUG_RETURN(0);
    }
    ST_SCHEMA_TABLE *schema_table;
    schema_table= find_schema_table(thd, &ptr->table_name);
    ptr->schema_table_name= ptr->table_name;
    ptr->schema_table= schema_table;
  }
  ptr->select_lex= this;
  /*
    We can't cache internal temporary tables between prepares as the
    table may be deleted before next exection.
 */
  ptr->cacheable_table= !table->is_derived_table();
  ptr->index_hints= index_hints_arg;
  ptr->option= option ? option->str : 0;
  /* check that used name is unique. Sequences are ignored */
  if (lock_type != TL_IGNORE && !ptr->sequence)
  {
    TABLE_LIST *first_table= table_list.first;
    if (lex->sql_command == SQLCOM_CREATE_VIEW)
      first_table= first_table ? first_table->next_local : NULL;
    for (TABLE_LIST *tables= first_table ;
	 tables ;
	 tables=tables->next_local)
    {
      if (unlikely(!my_strcasecmp(table_alias_charset, alias_str.str,
                                  tables->alias.str) &&
                   !cmp(&ptr->db, &tables->db) && ! tables->sequence))
      {
	my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str.str); /* purecov: tested */
	DBUG_RETURN(0);				/* purecov: tested */
      }
    }
  }
  /* Store the table reference preceding the current one. */
  if (table_list.elements > 0 && likely(!ptr->sequence))
  {
    /*
      table_list.next points to the last inserted TABLE_LIST->next_local'
      element
      We don't use the offsetof() macro here to avoid warnings from gcc
    */
    previous_table_ref= (TABLE_LIST*) ((char*) table_list.next -
                                       ((char*) &(ptr->next_local) -
                                        (char*) ptr));
    /*
      Set next_name_resolution_table of the previous table reference to point
      to the current table reference. In effect the list
      TABLE_LIST::next_name_resolution_table coincides with
      TABLE_LIST::next_local. Later this may be changed in
      store_top_level_join_columns() for NATURAL/USING joins.
    */
    previous_table_ref->next_name_resolution_table= ptr;
  }

  /*
    Link the current table reference in a local list (list for current select).
    Notice that as a side effect here we set the next_local field of the
    previous table reference to 'ptr'. Here we also add one element to the
    list 'table_list'.
    We don't store sequences into the local list to hide them from INSERT
    and SELECT.
  */
  if (likely(!ptr->sequence))
    table_list.link_in_list(ptr, &ptr->next_local);
  ptr->next_name_resolution_table= NULL;
#ifdef WITH_PARTITION_STORAGE_ENGINE
  ptr->partition_names= partition_names;
#endif /* WITH_PARTITION_STORAGE_ENGINE */
  /* Link table in global list (all used tables) */
  lex->add_to_query_tables(ptr);

  // Pure table aliases do not need to be locked:
  if (ptr->db.str && !(table_options & TL_OPTION_ALIAS))
  {
    ptr->mdl_request.init(MDL_key::TABLE, ptr->db.str, ptr->table_name.str,
                          mdl_type,
                          MDL_TRANSACTION);
  }
  DBUG_RETURN(ptr);
}