do_select(JOIN *join, Procedure *procedure)
{
  int rc= 0;
  enum_nested_loop_state error= NESTED_LOOP_OK;
  DBUG_ENTER("do_select");

  if (join->pushdown_query)
  {
    /* Select fields are in the temporary table */
    join->fields= &join->tmp_fields_list1;
    /* Setup HAVING to work with fields in temporary table */
    join->set_items_ref_array(join->items1);
    /* The storage engine will take care of the group by query result */
    int res= join->pushdown_query->execute(join);

    if (res)
      DBUG_RETURN(res);

    if (join->pushdown_query->store_data_in_temp_table)
    {
      JOIN_TAB *last_tab= join->join_tab + join->table_count -
                          join->exec_join_tab_cnt();
      last_tab->next_select= end_send;

      enum_nested_loop_state state= last_tab->aggr->end_send();
      if (state >= NESTED_LOOP_OK)
        state= sub_select(join, last_tab, true);

      if (state < NESTED_LOOP_OK)
        res= 1;

      if (join->result->send_eof())
        res= 1;
    }
    DBUG_RETURN(res);
  }

  join->procedure= procedure;
  join->duplicate_rows= join->send_records=0;
  if (join->only_const_tables() && !join->need_tmp)
  {
    Next_select_func end_select= setup_end_select_func(join, NULL);

    /*
      HAVING will be checked after processing aggregate functions,
      But WHERE should checked here (we alredy have read tables).
      Notice that make_join_select() splits all conditions in this case
      into two groups exec_const_cond and outer_ref_cond.
      If join->table_count == join->const_tables then it is
      sufficient to check only the condition pseudo_bits_cond.
    */
    DBUG_ASSERT(join->outer_ref_cond == NULL);
    if (!join->pseudo_bits_cond || join->pseudo_bits_cond->val_int())
    {
      // HAVING will be checked by end_select
      error= (*end_select)(join, 0, 0);
      if (error >= NESTED_LOOP_OK)
	error= (*end_select)(join, 0, 1);

      /*
        If we don't go through evaluate_join_record(), do the counting
        here.  join->send_records is increased on success in end_send(),
        so we don't touch it here.
      */
      join->join_examined_rows++;
      DBUG_ASSERT(join->join_examined_rows <= 1);
    }
    else if (join->send_row_on_empty_set())
    {
      table_map cleared_tables= (table_map) 0;
      if (end_select == end_send_group)
      {
        /*
          Was a grouping query but we did not find any rows. In this case
          we clear all tables to get null in any referenced fields,
          like in case of:
          SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL
        */
        clear_tables(join, &cleared_tables);
      }
      if (!join->having || join->having->val_int())
      {
        List<Item> *columns_list= (procedure ? &join->procedure_fields_list :
                                   join->fields);
        rc= join->result->send_data(*columns_list) > 0;
      }
      /*
        We have to remove the null markings from the tables as this table
        may be part of a sub query that is re-evaluated
      */
      if (cleared_tables)
        unclear_tables(join, &cleared_tables);
    }
    /*
      An error can happen when evaluating the conds
      (the join condition and piece of where clause
      relevant to this join table).
    */
    if (unlikely(join->thd->is_error()))
      error= NESTED_LOOP_ERROR;
  }
  else
  {
    DBUG_EXECUTE_IF("show_explain_probe_do_select",
                    if (dbug_user_var_equals_int(join->thd,
                                                 "show_explain_probe_select_id",
                                                 join->select_lex->select_number))
                          dbug_serve_apcs(join->thd, 1);
                   );

    JOIN_TAB *join_tab= join->join_tab +
                        (join->tables_list ? join->const_tables : 0);
    if (join->outer_ref_cond && !join->outer_ref_cond->val_int())
      error= NESTED_LOOP_NO_MORE_ROWS;
    else
      error= join->first_select(join,join_tab,0);
    if (error >= NESTED_LOOP_OK && likely(join->thd->killed != ABORT_QUERY))
      error= join->first_select(join,join_tab,1);
  }

  join->thd->limit_found_rows= join->send_records - join->duplicate_rows;

  if (error == NESTED_LOOP_NO_MORE_ROWS ||
      unlikely(join->thd->killed == ABORT_QUERY))
    error= NESTED_LOOP_OK;

  /*
    For "order by with limit", we cannot rely on send_records, but need
    to use the rowcount read originally into the join_tab applying the
    filesort. There cannot be any post-filtering conditions, nor any
    following join_tabs in this case, so this rowcount properly represents
    the correct number of qualifying rows.
  */
  if (join->order)
  {
    // Save # of found records prior to cleanup
    JOIN_TAB *sort_tab;
    JOIN_TAB *join_tab= join->join_tab;
    uint const_tables= join->const_tables;

    // Take record count from first non constant table or from last tmp table
    if (join->aggr_tables > 0)
      sort_tab= join_tab + join->top_join_tab_count + join->aggr_tables - 1;
    else
    {
      DBUG_ASSERT(!join->only_const_tables());
      sort_tab= join_tab + const_tables;
    }
    if (sort_tab->filesort &&
        join->select_options & OPTION_FOUND_ROWS &&
        sort_tab->filesort->sortorder &&
        sort_tab->filesort->limit != HA_POS_ERROR)
    {
      join->thd->limit_found_rows= sort_tab->records;
    }
  }

  {
    /*
      The following will unlock all cursors if the command wasn't an
      update command
    */
    join->join_free();			// Unlock all cursors
  }
  if (error == NESTED_LOOP_OK)
  {
    /*
      Sic: this branch works even if rc != 0, e.g. when
      send_data above returns an error.
    */
    if (unlikely(join->result->send_eof()))
      rc= 1;                                  // Don't send error
    DBUG_PRINT("info",("%ld records output", (long) join->send_records));
  }
  else
    rc= -1;
#ifndef DBUG_OFF
  if (rc)
  {
    DBUG_PRINT("error",("Error: do_select() failed"));
  }
#endif
  rc= join->thd->is_error() ? -1 : rc;
  DBUG_RETURN(rc);
}


static int rr_handle_error(READ_RECORD *info, int error)
{
  if (info->thd->killed)
  {
    info->thd->send_kill_message();
    return 1;
  }

  if (error == HA_ERR_END_OF_FILE)
    error= -1;
  else
  {
    if (info->print_error)
      info->table->file->print_error(error, MYF(0));
    if (error < 0)                            // Fix negative BDB errno
      error= 1;
  }
  return error;
}


static int rr_cmp(uchar *a,uchar *b)
{
  if (a[0] != b[0])
    return (int) a[0] - (int) b[0];
  if (a[1] != b[1])
    return (int) a[1] - (int) b[1];
  if (a[2] != b[2])
    return (int) a[2] - (int) b[2];
#if MAX_REFLENGTH == 4
  return (int) a[3] - (int) b[3];
#else
  if (a[3] != b[3])
    return (int) a[3] - (int) b[3];
  if (a[4] != b[4])
    return (int) a[4] - (int) b[4];
  if (a[5] != b[5])
    return (int) a[5] - (int) b[5];
  if (a[6] != b[6])
    return (int) a[6] - (int) b[6];
  return (int) a[7] - (int) b[7];
#endif
}


void st_select_lex_node::add_slave(st_select_lex_node *slave_arg)
{
  for (; slave; slave= slave->next)
    if (slave == slave_arg)
      return;

  if (slave)
  {
    st_select_lex_node *slave_arg_slave= slave_arg->slave;
    /* Insert in the front of list of slaves if any. */
    slave_arg->include_neighbour(slave);
    /* include_neighbour() sets slave_arg->slave=0, restore it. */
    slave_arg->slave= slave_arg_slave;
    /* Count on include_neighbour() setting the master. */
    DBUG_ASSERT(slave_arg->master == this);
  }
  else
  {
    slave= slave_arg;
    slave_arg->master= this;
  }
}


int my_wc_mb_utf8_escape_single_quote_and_backslash(CHARSET_INFO *cs,
                                                    my_wc_t wc,
                                                    uchar *str, uchar *end)
{
  return my_wc_mb_utf8_escape(cs, wc, str, end, '\'', '\\');
}


void st_select_lex::init_query()
{
  st_select_lex_node::init_query();
  table_list.empty();
  top_join_list.empty();
  join_list= &top_join_list;
  embedding= 0;
  leaf_tables_prep.empty();
  leaf_tables.empty();
  item_list.empty();
  min_max_opt_list.empty();
  join= 0;
  having= prep_having= where= prep_where= 0;
  cond_pushed_into_where= cond_pushed_into_having= 0;
  olap= UNSPECIFIED_OLAP_TYPE;
  having_fix_field= 0;
  having_fix_field_for_pushed_cond= 0;
  context.select_lex= this;
  context.init();
  /*
    Add the name resolution context of the current (sub)query to the
    stack of contexts for the whole query.
    TODO:
    push_context may return an error if there is no memory for a new
    element in the stack, however this method has no return value,
    thus push_context should be moved to a place where query
    initialization is checked for failure.
  */
  parent_lex->push_context(&context, parent_lex->thd->mem_root);
  cond_count= between_count= with_wild= 0;
  max_equal_elems= 0;
  ref_pointer_array.reset();
  select_n_where_fields= 0;
  select_n_reserved= 0;
  select_n_having_items= 0;
  n_sum_items= 0;
  n_child_sum_items= 0;
  hidden_bit_fields= 0;
  fields_in_window_functions= 0;
  subquery_in_having= explicit_limit= 0;
  is_item_list_lookup= 0;
  changed_elements= 0;
  first_natural_join_processing= 1;
  first_cond_optimization= 1;
  parsing_place= NO_MATTER;
  exclude_from_table_unique_test= no_wrap_view_item= FALSE;
  nest_level= 0;
  link_next= 0;
  prep_leaf_list_state= UNINIT;
  have_merged_subqueries= FALSE;
  bzero((char*) expr_cache_may_be_used, sizeof(expr_cache_may_be_used));
  select_list_tables= 0;
  m_non_agg_field_used= false;
  m_agg_func_used= false;
  window_specs.empty();
  window_funcs.empty();
}


bool st_select_lex::is_merged_child_of(st_select_lex *ancestor)
{
  bool all_merged= TRUE;
  for (SELECT_LEX *sl= this; sl && sl!=ancestor;
       sl=sl->outer_select())
  {
    Item *subs= sl->master_unit()->item;
    if (subs && subs->type() == Item::SUBSELECT_ITEM &&
        ((Item_subselect*)subs)->substype() == Item_subselect::IN_SUBS &&
        ((Item_in_subselect*)subs)->test_strategy(SUBS_SEMI_JOIN))
    {
      continue;
    }

    if (sl->master_unit()->derived &&
      sl->master_unit()->derived->is_merged_derived())
    {
      continue;
    }
    all_merged= FALSE;
    break;
  }
  return all_merged;
}


void st_select_lex::update_correlated_cache()
{
  TABLE_LIST *tl;
  List_iterator<TABLE_LIST> ti(leaf_tables);

  is_correlated= false;

  while ((tl= ti++))
  {
    //    is_correlated|= tl->is_with_table_recursive_reference();
    if (tl->on_expr)
      is_correlated|= MY_TEST(tl->on_expr->used_tables() & OUTER_REF_TABLE_BIT);
    for (TABLE_LIST *embedding= tl->embedding ; embedding ;
         embedding= embedding->embedding)
    {
      if (embedding->on_expr)
        is_correlated|= MY_TEST(embedding->on_expr->used_tables() &
                                OUTER_REF_TABLE_BIT);
    }
  }

  if (join->conds)
    is_correlated|= MY_TEST(join->conds->used_tables() & OUTER_REF_TABLE_BIT);

  is_correlated|= join->having_is_correlated;

  if (join->having)
    is_correlated|= MY_TEST(join->having->used_tables() & OUTER_REF_TABLE_BIT);

  if (join->tmp_having)
    is_correlated|= MY_TEST(join->tmp_having->used_tables() &
                            OUTER_REF_TABLE_BIT);

  Item *item;
  List_iterator_fast<Item> it(join->fields_list);
  while ((item= it++))
    is_correlated|= MY_TEST(item->used_tables() & OUTER_REF_TABLE_BIT);

  for (ORDER *order= group_list.first; order; order= order->next)
    is_correlated|= MY_TEST((*order->item)->used_tables() &
                            OUTER_REF_TABLE_BIT);

  if (!master_unit()->is_union())
  {
    for (ORDER *order= order_list.first; order; order= order->next)
      is_correlated|= MY_TEST((*order->item)->used_tables() &
                              OUTER_REF_TABLE_BIT);
  }

  if (!is_correlated)
    uncacheable&= ~UNCACHEABLE_DEPENDENT;
}


init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex)
{
  TABLE_LIST *table_list;
  Table_ident *table_ident;
  SELECT_LEX *select_lex= &lex->select_lex;
  Name_resolution_context *context= &select_lex->context;
  /*
    We will call the parser to create a part_info struct based on the
    partition string stored in the frm file.
    We will use a local lex object for this purpose. However we also
    need to set the Name_resolution_object for this lex object. We
    do this by using add_table_to_list where we add the table that
    we're working with to the Name_resolution_context.
  */
  thd->lex= lex;
  lex_start(thd);
  context->init();
  if ((!(table_ident= new Table_ident(thd,
                                      table->s->table_name,
                                      table->s->db, TRUE))) ||
      (!(table_list= select_lex->add_table_to_list(thd,
                                                   table_ident,
                                                   NULL,
                                                   0))))
    return TRUE;
  context->resolve_in_table_list_only(table_list);
  lex->use_only_table_context= TRUE;
  lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VCOL_EXPR;
  select_lex->cur_pos_in_select_list= UNDEF_POS;
  table->map= 1; //To ensure correct calculation of const item
  table_list->table= table;
  table_list->cacheable_table= false;
  return FALSE;
}


void st_select_lex::print_limit(THD *thd,
                                String *str,
                                enum_query_type query_type)
{
  SELECT_LEX_UNIT *unit= master_unit();
  Item_subselect *item= unit->item;

  if (item && unit->global_parameters() == this)
  {
    Item_subselect::subs_type subs_type= item->substype();
    if (subs_type == Item_subselect::IN_SUBS ||
        subs_type == Item_subselect::ALL_SUBS)
    {
      return;
    }
  }
  if (explicit_limit && select_limit)
  {
    str->append(STRING_WITH_LEN(" limit "));
    if (offset_limit)
    {
      offset_limit->print(str, query_type);
      str->append(',');
    }
    select_limit->print(str, query_type);
  }
}


uint st_select_lex::get_in_sum_expr()
{
  return in_sum_expr;
}


Item *get_tmp_table_item(THD *thd) { return this; }


  void bring_value()
  {
    if (result_type() == ROW_RESULT)
      orig_item->bring_value();
  }


  void set_extraction_flag(int flags)
  {
    marker &= ~EXTRACTION_MASK;
    marker|= flags;
  }


  Item_hex_string(THD *thd, const char *str, uint str_length):
    Item_hex_constant(thd, str, str_length) {}


  table_map not_null_tables() const
  {
    return depended_from ? 0 : (*ref)->not_null_tables();
  }


  bool eq(const Item *item, bool binary_cmp) const
  { return int_eq(value, item); }


Item_num(THD *thd): Item_basic_constant(thd) { collation.set_numeric(); }


  Item_string_with_introducer(THD *thd, const char *name_arg,
                              const char *str, uint length, CHARSET_INFO *tocs):
    Item_string(thd, name_arg, str, length, tocs)
  { }


  bool has_no_value() const
  {
    return state == NO_VALUE;
  }


virtual bool find_function_processor (void *arg) { return 0; }


  bool walk(Item_processor processor, bool walk_subquery, void *arg)
  {
    if (ref && *ref)
      return (*ref)->walk(processor, walk_subquery, arg) ||
             (this->*processor)(arg);
    else
      return FALSE;
  }


  void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
                     Sort_param *param) const
  {
    type_handler()->make_sort_key(to, item, sort_field, param);
  }


  bool agg_arg_charsets_for_string_result_with_comparison(DTCollation &c,
                                                          Item **items,
                                                          uint nitems,
                                                          int item_sep= 1)
  {
    uint flags= MY_COLL_ALLOW_SUPERSET_CONV |
                MY_COLL_ALLOW_COERCIBLE_CONV |
                MY_COLL_ALLOW_NUMERIC_CONV |
                MY_COLL_DISALLOW_NONE;
    return agg_arg_charsets(c, items, nitems, flags, item_sep);
  }


  virtual longlong val_datetime_packed()
  {
    MYSQL_TIME ltime;
    uint fuzzydate= TIME_FUZZY_DATES | TIME_INVALID_DATES;
    return get_date_with_conversion(&ltime, fuzzydate) ? 0 : pack_time(&ltime);
  }


  Item *get_copy(THD *thd, MEM_ROOT *mem_root)
  { return get_item_copy<Item_name_const>(thd, mem_root, this); }


  Item_cache(THD *thd, enum_field_types field_type_arg):
    Item_basic_constant(thd),
    Type_handler_hybrid_field_type(field_type_arg),
    example(0), cached_field(0),
    value_cached(0)
  {
    fixed= 1;
    maybe_null= 1;
    null_value= 1;
    null_value_inside= true;
  }


  bool null_inside()
  { return result_type() == ROW_RESULT ? orig_item->null_inside() : 0; }


  virtual void under_not(Item_func_not * upper
                         __attribute__((unused))) {};


  Item_args(THD *thd, Item *a, Item *b, Item *c, Item *d, Item* e)
  {
    arg_count= 5;
    if ((args= (Item**) thd_alloc(thd, sizeof(Item*) * 5)))
    {
      arg_count= 5;
      args[0]= a; args[1]= b; args[2]= c; args[3]= d; args[4]= e;
    }
  }


  bool walk(Item_processor processor, bool walk_subquery, void *arg)
  {
    return (*ref)->walk(processor, walk_subquery, arg) ||
           (this->*processor)(arg);
  }


char_to_byte_length_safe(size_t char_length_arg, uint32 mbmaxlen_arg)
{
  ulonglong tmp= ((ulonglong) char_length_arg) * mbmaxlen_arg;
  return tmp > UINT_MAX32 ? UINT_MAX32 : static_cast<uint32>(tmp);
}


  st_select_lex *outer_select()
  {
    return (outer_context ?
            outer_context->select_lex :
            NULL);
  }


  void save_in_result_field(bool no_conversions)
  {
    if (check_null_ref())
      result_field->set_null();
    else
      Item_direct_ref::save_in_result_field(no_conversions);
  }


enum_field_types field_type() const { return this_item()->field_type(); }


  void set(const Type_std_attributes *other)
  {
    *this= *other;
  }


  bool enumerate_field_refs_processor(void *arg)
  { return orig_item->enumerate_field_refs_processor(arg); }


  void split_sum_func2_example(THD *thd,  Ref_ptr_array ref_pointer_array,
                               List<Item> &fields, uint flags)
  {
    example->split_sum_func2(thd, ref_pointer_array, fields, &example, flags);
  }


  void clear_extraction_flag()
  {
    marker &= ~EXTRACTION_MASK;
  }


  void set(const DTCollation &dt)
  {
    collation= dt.collation;
    derivation= dt.derivation;
    repertoire= dt.repertoire;
  }


  enum Type type() const
  {
    return item_type;
  }


  int get_extraction_flag()
  { return  marker & EXTRACTION_MASK; }


  int save_in_field(Field *field, bool no_conversions)
  {
    field->set_notnull();
    return field->store(str_value.ptr(), str_value.length(),
                        collation.collation);
  }


virtual bool limit_index_condition_pushdown_processor(void *arg) { return 0; }


  Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
  {
    return const_charset_converter(thd, tocs, true);
  }


  Item_float(THD *thd, double value_par, uint decimal_par):
    Item_num(thd), presentation(0), value(value_par)
  {
    decimals= (uint8) decimal_par;
    fixed= 1;
  }


Item *get_orig_item() const { return orig_item; }


  longlong val_temporal_packed(const Item *other)
  {
    return val_temporal_packed(field_type_for_temporal_comparison(other));
  }


virtual void mark_as_condition_AND_part(TABLE_LIST *embedding) {};


  bool is_null()
  {
    if (check_null_ref())
      return 1;
    else
      return Item_direct_ref::is_null();
  }


  double val_real_from_item(Item *item)
  {
    DBUG_ASSERT(fixed == 1);
    double value= item->val_real();
    null_value= item->null_value;
    return value;
  }


  virtual void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
                              List<Item> &fields, uint flags) {}


  void used_tables_and_const_cache_join(const Item *item)
  {
    used_tables_cache|= item->used_tables();
    const_item_cache&= item->const_item();
  }


  void set_null_ref_table()
  {
    if (!view->is_inner_table_of_outer_join() ||
        !(null_ref_table= view->get_real_join_table()))
      null_ref_table= NO_NULL_TABLE;
  }


TABLE *get_null_ref_table() const { return null_ref_table; }


virtual bool register_field_in_write_map(void *arg) { return 0; }


virtual enum precedence precedence() const { return DEFAULT_PRECEDENCE; }


  bool needs_charset_converter(CHARSET_INFO *tocs)
  {
    // Pass 1 as length to force conversion if tocs->mbminlen>1.
    return needs_charset_converter(1, tocs);
  }


  void fix_type(Type type)
  {
    item_type= type;
    fixed= true;
  }


  Item_int(THD *thd, ulonglong i, uint length= MY_INT64_NUM_DECIMAL_DIGITS):
    Item_num(thd), value((longlong)i)
    { max_length=length; fixed= 1; unsigned_flag= 1; }


  bool eq(const Item *item, bool binary_cmp) const
  {
    return str_eq(&str_value, item, binary_cmp);
  }


  const char *field_name_or_null()
  { return real_item()->type() == Item::FIELD_ITEM ? name : NULL; }


  bool str_eq(const String *value, const Item *item, bool binary_cmp) const
  {
    DBUG_ASSERT(is_basic_value(STRING_ITEM));
    return is_basic_value(item, STRING_ITEM) &&
           str_eq(value, ((Item_basic_value*)item)->val_str(NULL),
                  item->collation.collation, binary_cmp);
  }


virtual bool collect_item_field_processor(void *arg) { return 0; }


  bool convert_time_to_datetime(THD *thd, MYSQL_TIME *ltime, ulonglong fuzzydate)
  {
    MYSQL_TIME tmp;
    if (time_to_datetime_with_warn(thd, ltime, &tmp, fuzzydate))
      return null_value= true;
    *ltime= tmp;
    return false;
  }


  virtual bool is_expensive()
  {
    if (is_expensive_cache < 0)
      is_expensive_cache= walk(&Item::is_expensive_processor, 0, NULL);
    return MY_TEST(is_expensive_cache);
  }


  Item *get_copy(THD *thd, MEM_ROOT *mem_root)
  { return get_item_copy<Item_null>(thd, mem_root, this); }


  Rewritable_query_parameter(uint pos_in_q= 0, uint len_in_q= 0)
    : pos_in_query(pos_in_q), len_in_query(len_in_q),
      limit_clause_param(false)
  { }


  void fetch_value_from(Item *new_item)
  {
    Item *save= item;
    item= new_item;
    cmp();
    item= save;
  }


  bool excl_dep_on_table(table_map tab_map)
  {
    table_map used= used_tables();
    if (used & OUTER_REF_TABLE_BIT)
      return false;
    return (used == tab_map) || (*ref)->excl_dep_on_table(tab_map);
  }


  Item_cache_real(THD *thd): Item_cache(thd, MYSQL_TYPE_DOUBLE),
    value(0) {}


  void save_in_result_field(bool no_conversions)
  {
    outer_ref->save_org_in_field(result_field, NULL);
  }


  Item_string(THD *thd, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE):
    Item_basic_constant(thd)
  {
    collation.set(cs, dv);
    max_length= 0;
    set_name(thd, NULL, 0, system_charset_info);
    decimals= NOT_FIXED_DEC;
    fixed= 1;
  }


  virtual Item *derived_field_transformer_for_where(THD *thd, uchar *arg)
  { return this; }


virtual uint exists2in_reserved_items() { return 0; };


bool check_vcol_func_processor(void *int_arg) {return FALSE;}


  String *val_str(String* tmp)
  {
    if (check_null_ref())
      return NULL;
    else
      return Item_direct_ref::val_str(tmp);
  }


  bool agg_arg_charsets_for_comparison(DTCollation &c,
                                       Item **items, uint nitems,
                                       int item_sep= 1)
  {
    uint flags= MY_COLL_ALLOW_SUPERSET_CONV |
                MY_COLL_ALLOW_COERCIBLE_CONV |
                MY_COLL_DISALLOW_NONE;
    return agg_arg_charsets(c, items, nitems, flags, item_sep);
  }


static my_bool translog_callback_delete_all(const char *directory,
                                            const char *filename)
{
  char complete_name[FN_REFLEN];
  fn_format(complete_name, filename, directory, "", MYF(MY_UNPACK_FILENAME));
  return mysql_file_delete(key_file_translog, complete_name, MYF(MY_WME));
}


bool ha_maria::auto_repair(int error) const
{
  /* Always auto-repair moved tables (error == HA_ERR_OLD_FILE) */
  return ((MY_TEST(maria_recover_options & HA_RECOVER_ANY) &&
           error == HA_ERR_CRASHED_ON_USAGE) ||
          error == HA_ERR_OLD_FILE);

}


bool ha_maria::check_and_repair(THD *thd)
{
  int error, crashed;
  HA_CHECK_OPT check_opt;
  const CSET_STRING query_backup= thd->query_string;
  DBUG_ENTER("ha_maria::check_and_repair");

  check_opt.init();
  check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;

  error= 1;
  if (!aria_readonly &&
      (file->s->state.changed & (STATE_CRASHED_FLAGS | STATE_MOVED)) ==
      STATE_MOVED)
  {
    /* Remove error about crashed table */
    thd->get_stmt_da()->clear_warning_info(thd->query_id);
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
                        ER_CRASHED_ON_USAGE,
                        "Zerofilling moved table %s", table->s->path.str);
    sql_print_information("Zerofilling moved table:  '%s'",
                          table->s->path.str);
    if (!(error= zerofill(thd, &check_opt)))
      DBUG_RETURN(0);
  }

  /*
    if we got this far - the table is crashed.
    but don't auto-repair if maria_recover_options is not set
  */
  if (!maria_recover_options)
    DBUG_RETURN(error);

  error= 0;
  // Don't use quick if deleted rows
  if (!file->state->del && (maria_recover_options & HA_RECOVER_QUICK))
    check_opt.flags |= T_QUICK;

  thd->set_query((char*) table->s->table_name.str,
                 (uint) table->s->table_name.length, system_charset_info);

  if (!(crashed= maria_is_crashed(file)))
  {
    sql_print_warning("Checking table:   '%s'", table->s->path.str);
    crashed= check(thd, &check_opt);
  }

  if (crashed)
  {
    bool save_log_all_errors;
    sql_print_warning("Recovering table: '%s'", table->s->path.str);
    save_log_all_errors= thd->log_all_errors;
    thd->log_all_errors|= (thd->variables.log_warnings > 2);
    check_opt.flags=
      ((maria_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
       (maria_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
       T_AUTO_REPAIR);
    if (repair(thd, &check_opt))
      error= 1;
    thd->log_all_errors= save_log_all_errors;
  }
  thd->set_query(query_backup);
  DBUG_RETURN(error);
}


ha_rows ha_maria::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
                                       uint key_parts, uint *bufsz,
                                       uint *flags, Cost_estimate *cost)
{
  ds_mrr.init(this, table);
  return ds_mrr.dsmrr_info(keyno, n_ranges, keys, key_parts, bufsz, flags, cost);
}


bool ha_maria::has_active_transaction(THD *thd)
{
  return (maria_hton && THD_TRN);
}


int ha_maria::indexes_are_disabled(void)
{
  return maria_indexes_are_disabled(file);
}


int ha_maria::delete_row(const uchar * buf)
{
  CHECK_UNTIL_WE_FULLY_IMPLEMENTED_VERSIONING("DELETE in WRITE CONCURRENT");
  return maria_delete(file, buf);
}


const char *ha_maria::index_type(uint key_number)
{
  return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
          "FULLTEXT" :
          (table->key_info[key_number].flags & HA_SPATIAL) ?
          "SPATIAL" :
          (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
          "RTREE" : "BTREE");
}


static int maria_hton_panic(handlerton *hton, ha_panic_function flag)
{
  /* If no background checkpoints, we need to do one now */
  int ret=0;

  if (!checkpoint_interval && !aria_readonly)
    ret= ma_checkpoint_execute(CHECKPOINT_FULL, FALSE);

  ret|= maria_panic(flag);

  maria_hton= 0;
  return ret;
}


int ha_maria::zerofill(THD * thd, HA_CHECK_OPT *check_opt)
{
  int error;
  HA_CHECK *param= (HA_CHECK*) thd->alloc(sizeof *param);
  TRN *old_trn;
  MARIA_SHARE *share= file->s;

  if (!file || !param)
    return HA_ADMIN_INTERNAL_ERROR;

  unmap_file(file);
  old_trn= file->trn;
  maria_chk_init(param);
  param->thd= thd;
  param->op_name= "zerofill";
  param->testflag= check_opt->flags | T_SILENT | T_ZEROFILL;
  param->orig_sort_buffer_length= THDVAR(thd, sort_buffer_size);
  param->db_name= table->s->db.str;
  param->table_name= table->alias.c_ptr();

  error=maria_zerofill(param, file, share->open_file_name.str);

  /* Reset trn, that may have been set by repair */
  if (old_trn && old_trn != file->trn)
    _ma_set_trn_for_table(file, old_trn);

  if (!error)
  {
    TrID create_trid= trnman_get_min_safe_trid();
    mysql_mutex_lock(&share->intern_lock);
    share->state.changed|= STATE_NOT_MOVABLE;
    maria_update_state_info(param, file, UPDATE_TIME | UPDATE_OPEN_COUNT);
    _ma_update_state_lsns_sub(share, LSN_IMPOSSIBLE, create_trid,
                              TRUE, TRUE);
    mysql_mutex_unlock(&share->intern_lock);
  }
  return error;
}


int ha_maria::rnd_pos(uchar *buf, uchar *pos)
{
  register_handler(file);
  int error= maria_rrnd(file, buf, my_get_ptr(pos, ref_length));
  return error;
}


static void reset_thd_trn(THD *thd, MARIA_HA *first_table)
{
  DBUG_ENTER("reset_thd_trn");
  thd_set_ha_data(thd, maria_hton, 0);
  MARIA_HA *next;
  for (MARIA_HA *table= first_table; table ; table= next)
  {
    next= table->trn_next;
    _ma_reset_trn_for_table(table);

    /*
      If table has changed by this statement, invalidate it from the query
      cache
    */
    if (table->row_changes != table->start_row_changes)
    {
      table->start_row_changes= table->row_changes;
      DBUG_ASSERT(table->s->chst_invalidator != NULL);
      (*table->s->chst_invalidator)(table->s->data_file_name.str);
    }
  }
  DBUG_VOID_RETURN;
}


void Item_trigger_field::setup_field(THD *thd, TABLE *table,
                                     GRANT_INFO *table_grant_info)
{
  /*
    It is too early to mark fields used here, because before execution
    of statement that will invoke trigger other statements may use same
    TABLE object, so all such mark-up will be wiped out.
    So instead we do it in Table_triggers_list::mark_fields_used()
    method which is called during execution of these statements.
  */
  enum_column_usage saved_column_usage= thd->column_usage;
  thd->column_usage= want_privilege == SELECT_ACL ? COLUMNS_READ
                                                  : COLUMNS_WRITE;
  /*
    Try to find field by its name and if it will be found
    set field_idx properly.
  */
  (void)find_field_in_table(thd, table, field_name.str, field_name.length,
                            0, &field_idx);
  thd->column_usage= saved_column_usage;
  triggers= table->triggers;
  table_grants= table_grant_info;
}


unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
             uint check_flag)
{
  TABLE_LIST *dup;

  table= table->find_table_for_update();

  if (table->table &&
      table->table->file->ha_table_flags() & HA_CAN_MULTISTEP_MERGE)
  {
    TABLE_LIST *child;
    dup= NULL;
    /* Check duplicates of all merge children. */
    for (child= table->next_global; child;
         child= child->next_global)
    {
      if (child->table &&
          child->table->file->ha_table_flags() & HA_CAN_MULTISTEP_MERGE)
        continue;

      /*
        Ensure that the child has one parent that is the table that is
        updated.
      */
      TABLE_LIST *tmp_parent= child;
      while ((tmp_parent= tmp_parent->parent_l))
      {
        if (tmp_parent == table)
          break;
      }
      if (!tmp_parent)
        break;

      if ((dup= find_dup_table(thd, child, child->next_global, check_flag)))
        break;
    }
  }
  else
    dup= find_dup_table(thd, table, table_list, check_flag);
  return dup;
}


Item_splocal::this_item() const
{
  DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
  DBUG_ASSERT(fixed);
  return get_variable(m_thd->spcont);
}


bool Item_case_expr::fix_fields(THD *thd, Item **ref)
{
  Item *item= thd->spcont->get_case_expr(m_case_expr_id);
  return fix_fields_from_item(thd, ref, item);
}


bool Item_insert_value::eq(const Item *item, bool binary_cmp) const
{
  return item->type() == INSERT_VALUE_ITEM &&
    ((Item_insert_value *)item)->arg->eq(arg, binary_cmp);
}


String *Item::val_str_ascii_revert_empty_string_is_null(THD *thd, String *str)
{
  String *res= val_str_ascii(str);
  if (!res && (thd->variables.sql_mode & MODE_EMPTY_STRING_IS_NULL))
  {
    null_value= false;
    str->set("", 0, &my_charset_latin1);
    return str;
  }
  return res;
}


void Item_param::set_default()
{
  m_is_settable_routine_parameter= false;
  state= DEFAULT_VALUE;
  fixed= true;
  /*
    When Item_param is set to DEFAULT_VALUE:
    - its val_str() and val_decimal() return NULL
    - get_date() returns true
    It's important also to have null_value==true for DEFAULT_VALUE.
    Otherwise the callers of val_xxx() and get_date(), e.g. Item::send(),
    can misbehave (e.g. crash on asserts).
  */
  null_value= true;
}


Item_splocal_row_field::this_item() const
{
  DBUG_ASSERT(m_sp == m_thd->spcont->m_sp);
  DBUG_ASSERT(fixed);
  return get_variable(m_thd->spcont)->element_index(m_field_idx);
}


void Item_trigger_field::print(String *str, enum_query_type query_type)
{
  str->append((row_version == NEW_ROW) ? "NEW" : "OLD", 3);
  str->append('.');
  str->append(&field_name);
}


static inline bool derived_table_optimization_done(TABLE_LIST *table)
{
  return table->derived &&
      (table->derived->is_excluded() ||
       table->is_materialized_derived());
}


char *generate_partition_syntax_for_frm(THD *thd, partition_info *part_info,
                                        uint *buf_length,
                                        HA_CREATE_INFO *create_info,
                                        Alter_info *alter_info)
{
  sql_mode_t old_mode= thd->variables.sql_mode;
  thd->variables.sql_mode &= ~MODE_ANSI_QUOTES;
  char *res= generate_partition_syntax(thd, part_info, buf_length,
                                             true, create_info, alter_info);
  thd->variables.sql_mode= old_mode;
  return res;
}


int Item::save_str_in_field(Field *field, bool no_conversions)
{
  String *result;
  CHARSET_INFO *cs= collation.collation;
  char buff[MAX_FIELD_WIDTH];		// Alloc buffer for small columns
  str_value.set_quick(buff, sizeof(buff), cs);
  result=val_str(&str_value);
  if (null_value)
  {
    str_value.set_quick(0, 0, cs);
    return set_field_to_null_with_conversions(field, no_conversions);
  }

  /* NOTE: If null_value == FALSE, "result" must be not NULL.  */

  field->set_notnull();
  int error= field->store(result->ptr(),result->length(),cs);
  str_value.set_quick(0, 0, cs);
  return error;
}


static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
{
  char path[FN_REFLEN+1];
  partition_info *part_info= lpt->table->part_info;
  List_iterator<partition_element> part_it(part_info->partitions);
  int error;
  DBUG_ENTER("mysql_drop_partitions");

  DBUG_ASSERT(lpt->thd->mdl_context.is_lock_owner(MDL_key::TABLE,
                                                lpt->table->s->db.str,
                                                lpt->table->s->table_name.str,
                                                MDL_EXCLUSIVE));

  build_table_filename(path, sizeof(path) - 1, lpt->db.str, lpt->table_name.str, "", 0);
  if ((error= lpt->table->file->ha_drop_partitions(path)))
  {
    lpt->table->file->print_error(error, MYF(0));
    DBUG_RETURN(TRUE);
  }
  DBUG_RETURN(FALSE);
}


Item *Item_direct_view_ref::derived_field_transformer_for_where(THD *thd,
                                                                uchar *arg)
{
  if ((*ref)->marker & SUBSTITUTION_FL)
    return (*ref);
  if (item_equal)
  {
    st_select_lex *sel= (st_select_lex *)arg;
    Item *producing_item= find_producing_item(this, sel);
    DBUG_ASSERT (producing_item != NULL);
    return producing_item->build_clone(thd);
  }
  return (*ref);
}


Item *Item_bool::neg_transformer(THD *thd)
{
  value= !value;
  name= null_clex_str;
  return this;
}


longlong Item_default_value::val_int_result()
{
  calculate();
  return Item_field::val_int_result();
}


void TABLE::evaluate_update_default_function()
{
  DBUG_ENTER("TABLE::evaluate_update_default_function");

  if (s->has_update_default_function)
    for (Field **field_ptr= default_field; *field_ptr ; field_ptr++)
    {
      Field *field= (*field_ptr);
      if (!field->has_explicit_value() && field->has_update_default_function())
        field->set_time();
    }
  DBUG_VOID_RETURN;
}


bool TABLE::update_const_key_parts(COND *conds)
{
  bzero((char*) const_key_parts, sizeof(key_part_map) * s->keys);

  if (conds == NULL)
    return FALSE;

  for (uint index= 0; index < s->keys; index++)
  {
    KEY_PART_INFO *keyinfo= key_info[index].key_part;
    KEY_PART_INFO *keyinfo_end= keyinfo + key_info[index].user_defined_key_parts;

    for (key_part_map part_map= (key_part_map)1;
        keyinfo < keyinfo_end;
        keyinfo++, part_map<<= 1)
    {
      if (const_expression_in_where(conds, NULL, keyinfo->field))
        const_key_parts[index]|= part_map;
    }
  }
  return FALSE;
}


const char *dbug_print_unit(SELECT_LEX_UNIT *un)
{
  char *buf= dbug_item_print_buf;
  String str(buf, sizeof(dbug_item_print_buf), &my_charset_bin);
  str.length(0);
  if (!un)
    return "(SELECT_LEX_UNIT*)NULL";

  THD *thd= current_thd;
  ulonglong save_option_bits= thd->variables.option_bits;
  thd->variables.option_bits &= ~OPTION_QUOTE_SHOW_CREATE;

  un->print(&str, QT_EXPLAIN);

  thd->variables.option_bits= save_option_bits;

  if (str.c_ptr() == buf)
    return buf;
  else
    return "Couldn't fit into buffer";
}


open_and_process_table(THD *thd, TABLE_LIST *tables, uint *counter, uint flags,
                       Prelocking_strategy *prelocking_strategy,
                       bool has_prelocking_list, Open_table_context *ot_ctx)
{
  bool error= FALSE;
  bool safe_to_ignore_table= FALSE;
  LEX *lex= thd->lex;
  DBUG_ENTER("open_and_process_table");
  DEBUG_SYNC(thd, "open_and_process_table");

  /*
    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)
    {
      if (!tables->is_derived())
        tables->set_derived();
      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;
    tables->table_name= tables->view_name;
  }

  if (!tables->derived && is_infoschema_db(&tables->db))
  {
    /*
      Check whether the information schema contains a table
      whose name is tables->schema_table_name
    */
    ST_SCHEMA_TABLE *schema_table= tables->schema_table;
    if (!schema_table ||
        (schema_table->hidden &&
         ((sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0 ||
          /*
            this check is used for show columns|keys from I_S hidden table
          */
          lex->sql_command == SQLCOM_SHOW_FIELDS ||
          lex->sql_command == SQLCOM_SHOW_KEYS)))
    {
      my_error(ER_UNKNOWN_TABLE, MYF(0),
               tables->table_name.str, INFORMATION_SCHEMA_NAME.str);
      DBUG_RETURN(1);
    }
  }
  /*
    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)
    {
      MDL_ticket *mdl_ticket;
      /*
        We still need to take a MDL lock on the merged view to protect
        it from concurrent changes.
      */
      if (!open_table_get_mdl_lock(thd, ot_ctx, &tables->mdl_request,
                                   flags, &mdl_ticket) &&
          mdl_ticket != NULL)
        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))
    {
      goto end;
    }
    error= TRUE;
    goto end;
  }
  DBUG_PRINT("tcache", ("opening table: '%s'.'%s'  item: %p",
                        tables->db.str, tables->table_name.str, tables));
  (*counter)++;

  /*
    Not a placeholder: must be a base/temporary table or a view. Let us open it.
  */
  if (tables->table)
  {
    /*
      If this TABLE_LIST object has an associated open TABLE object
      (TABLE_LIST::table is not NULL), that TABLE object must be a pre-opened
      temporary table or SEQUENCE (see sequence_insert()).
    */
    DBUG_ASSERT(is_temporary_table(tables) || tables->table->s->sequence);
    if (tables->sequence && tables->table->s->table_type != TABLE_TYPE_SEQUENCE)
    {
        my_error(ER_NOT_SEQUENCE, MYF(0), tables->db.str, tables->alias.str);
        DBUG_RETURN(true);
    }
  }
  else if (tables->open_type == OT_TEMPORARY_ONLY)
  {
    /*
      OT_TEMPORARY_ONLY means that we are in CREATE TEMPORARY TABLE statement.
      Also such table list element can't correspond to prelocking placeholder
      or to underlying table of merge table.
      So existing temporary table should have been preopened by this moment
      and we can simply continue without trying to open temporary or base
      table.
    */
    DBUG_ASSERT(tables->open_strategy);
    DBUG_ASSERT(!tables->prelocking_placeholder);
    DBUG_ASSERT(!tables->parent_l);
    DBUG_RETURN(0);
  }

  /* Not a placeholder: must be a base table or a view. Let us open it. */
  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.
    */
    No_such_table_error_handler no_such_table_handler;
    thd->push_internal_handler(&no_such_table_handler);

    /*
      We're opening a table from the prelocking list.

      Since this table list element might have been added after pre-opening
      of temporary tables we have to try to open temporary table for it.

      We can't simply skip this table list element and postpone opening of
      temporary table till the execution of substatement for several reasons:
      - Temporary table can be a MERGE table with base underlying tables,
        so its underlying tables has to be properly open and locked at
        prelocking stage.
      - Temporary table can be a MERGE table and we might be in PREPARE
        phase for a prepared statement. In this case it is important to call
        HA_ATTACH_CHILDREN for all merge children.
        This is necessary because merge children remember "TABLE_SHARE ref type"
        and "TABLE_SHARE def version" in the HA_ATTACH_CHILDREN operation.
        If HA_ATTACH_CHILDREN is not called, these attributes are not set.
        Then, during the first EXECUTE, those attributes need to be updated.
        That would cause statement re-preparing (because changing those
        attributes during EXECUTE is caught by THD::m_reprepare_observers).
        The problem is that since those attributes are not set in merge
        children, another round of PREPARE will not help.
    */
    error= thd->open_temporary_table(tables);

    if (!error && !tables->table)
      error= open_table(thd, tables, ot_ctx);

    thd->pop_internal_handler();
    safe_to_ignore_table= no_such_table_handler.safely_trapped_errors();
  }
  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= thd->open_temporary_table(tables);

    if (!error && !tables->table)
      error= open_table(thd, tables, ot_ctx);

    thd->pop_internal_handler();
    safe_to_ignore_table= repair_mrg_table_handler.safely_trapped_errors();
  }
  else
  {
    if (tables->parent_l)
    {
      /*
        Even if we are opening table not from the prelocking list we
        still might need to look for a temporary table if this table
        list element corresponds to underlying table of a merge table.
      */
      error= thd->open_temporary_table(tables);
    }

    if (!error && !tables->table)
      error= open_table(thd, tables, ot_ctx);
  }

  if (unlikely(error))
  {
    if (! ot_ctx->can_recover_from_failed_open() && safe_to_ignore_table)
    {
      DBUG_PRINT("info", ("open_table: ignoring table '%s'.'%s'",
                          tables->db.str, tables->alias.str));
      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;

  error= extend_table_list(thd, tables, prelocking_strategy, has_prelocking_list);
  if (unlikely(error))
    goto end;

  /* Copy grant information from TABLE_LIST instance to TABLE one. */
  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 (unlikely(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 (unlikely(error))
      goto end;
  }

end:
  DBUG_RETURN(error);
}


static void mysql57_calculate_null_position(TABLE_SHARE *share,
                                            uchar **null_pos,
                                            uint *null_bit_pos,
                                            const uchar *strpos,
                                            const uchar *vcol_screen_pos)
{
  uint field_pack_length= 17;

  for (uint i=0 ; i < share->fields; i++, strpos+= field_pack_length)
  {
    uint field_length, pack_flag;
    enum_field_types field_type;

    if ((strpos[10] & MYSQL57_GENERATED_FIELD))
    {
      /* Skip virtual (not stored) generated field */
      bool stored_in_db= vcol_screen_pos[3];
      vcol_screen_pos+= (uint2korr(vcol_screen_pos + 1) +
                         MYSQL57_GCOL_HEADER_SIZE);
      if (! stored_in_db)
        continue;
    }
    field_length= uint2korr(strpos+3);
    pack_flag=    uint2korr(strpos+8);
    field_type=   (enum_field_types) (uint) strpos[13];
    if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag))
    {
      if (((*null_bit_pos)+= field_length & 7) > 7)
      {
        (*null_pos)++;
        (*null_bit_pos)-= 8;
      }
    }
    if (f_maybe_null(pack_flag))
    {
      if (!((*null_bit_pos)= ((*null_bit_pos) + 1) & 7))
        (*null_pos)++;
    }
  }
}


void Item_field::save_in_result_field(bool no_conversions)
{
  bool unused;
  save_field_in_field(field, &unused, result_field, no_conversions);
}


void init_mdl_requests(TABLE_LIST *table_list)
{
  for ( ; table_list ; table_list= table_list->next_global)
    table_list->mdl_request.init(MDL_key::TABLE,
                                 table_list->db.str, table_list->table_name.str,
                                 table_list->lock_type >= TL_WRITE_ALLOW_WRITE ?
                                 MDL_SHARED_WRITE : MDL_SHARED_READ,
                                 MDL_TRANSACTION);
}


Item *Item_int::clone_item(THD *thd)
{
  return new (thd->mem_root) Item_int(thd, name.str, value, max_length, unsigned_flag);
}


bool TR_table::query(MYSQL_TIME &commit_time, bool backwards)
{
  if (!table && open())
    return false;
  SQL_SELECT_auto select;
  READ_RECORD info;
  int error;
  List<TABLE_LIST> dummy;
  SELECT_LEX &slex= thd->lex->select_lex;
  Name_resolution_context_backup backup(slex.context, *this);
  Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_COMMIT_TS]);
  Item *value= newx Item_datetime_literal(thd, &commit_time, 6);
  COND *conds;
  if (backwards)
    conds= newx Item_func_ge(thd, field, value);
  else
    conds= newx Item_func_le(thd, field, value);
  if (unlikely((error= setup_conds(thd, this, dummy, &conds))))
    return false;
  // FIXME: (performance) force index 'commit_timestamp'
  select= make_select(table, 0, 0, conds, NULL, 0, &error);
  if (unlikely(error || !select))
    return false;
  error= init_read_record(&info, thd, table, select, NULL,
                          1 /* use_record_cache */, true /* print_error */,
                          false /* disable_rr_cache */);

  // With PK by transaction_id the records are ordered by PK, so we have to
  // scan TRT fully and collect min (backwards == true)
  // or max (backwards == false) stats.
  bool found= false;
  MYSQL_TIME found_ts;
  while (!(error= info.read_record()) && !thd->killed && !thd->is_error())
  {
    int res= select->skip_record(thd);
    if (res > 0)
    {
      MYSQL_TIME commit_ts;
      if ((*this)[FLD_COMMIT_TS]->get_date(&commit_ts, 0))
      {
        found= false;
        break;
      }
      int c;
      if (!found || ((c= my_time_compare(&commit_ts, &found_ts)) &&
        (backwards ? c < 0 : c > 0)))
      {
        found_ts= commit_ts;
        found= true;
        // TODO: (performance) make ORDER DESC and break after first found.
        // Otherwise it is O(n) scan (+copy)!
        store_record(table, record[1]);
      }
    }
    else if (res < 0)
    {
      found= false;
      break;
    }
 }
  if (found)
    restore_record(table, record[1]);
  return found;
}


bool Item_outer_ref::fix_fields(THD *thd, Item **reference)
{
  bool err;
  /* outer_ref->check_cols() will be made in Item_direct_ref::fix_fields */
  if ((*ref) && (*ref)->fix_fields_if_needed(thd, reference))
    return TRUE;
  err= Item_direct_ref::fix_fields(thd, reference);
  if (!outer_ref)
    outer_ref= *ref;
  if ((*ref)->type() == Item::FIELD_ITEM)
    table_name= ((Item_field*)outer_ref)->table_name;
  return err;
}


bool Item_default_value::val_bool_result()
{
  calculate();
  return Item_field::val_bool_result();
}


fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
            bool ignore_errors, bool use_value)
{
  List_iterator_fast<Item> v(values);
  List<TABLE> tbl_list;
  Item *value;
  Field *field;
  bool abort_on_warning_saved= thd->abort_on_warning;
  uint autoinc_index= table->next_number_field
                        ? table->next_number_field->field_index
                        : ~0U;
  DBUG_ENTER("fill_record");
  if (!*ptr)
  {
    /* No fields to update, quite strange!*/
    DBUG_RETURN(0);
  }

  /*
    On INSERT or UPDATE fields are checked to be from the same table,
    thus we safely can take table from the first field.
  */
  DBUG_ASSERT((*ptr)->table == table);

  /*
    Reset the table->auto_increment_field_not_null as it is valid for
    only one row.
  */
  table->auto_increment_field_not_null= FALSE;
  while ((field = *ptr++) && ! thd->is_error())
  {
    /* Ensure that all fields are from the same table */
    DBUG_ASSERT(field->table == table);

    if (unlikely(field->invisible))
      continue;
    else
      value=v++;

    bool vers_sys_field= table->versioned() && field->vers_sys_field();

    if (field->field_index == autoinc_index)
      table->auto_increment_field_not_null= TRUE;
    if ((unlikely(field->vcol_info) || (vers_sys_field && !ignore_errors)) &&
        !value->vcol_assignment_allowed_value() &&
        table->s->table_category != TABLE_CATEGORY_TEMPORARY)
    {
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN,
                          ER_THD(thd, ER_WARNING_NON_DEFAULT_VALUE_FOR_GENERATED_COLUMN),
                          field->field_name.str, table->s->table_name.str);
      if (vers_sys_field)
        continue;
    }

    if (use_value)
      value->save_val(field);
    else
      if (value->save_in_field(field, 0) < 0)
        goto err;
    field->set_has_explicit_value();
  }
  thd->abort_on_warning= FALSE;
  if (table->default_field &&
      table->update_default_fields(ignore_errors))
    goto err;
  /* Update virtual fields */
  if (table->vfield &&
      table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE))
    goto err;
  if (table->versioned())
    table->vers_update_fields();
  thd->abort_on_warning= abort_on_warning_saved;
  DBUG_RETURN(thd->is_error());

err:
  thd->abort_on_warning= abort_on_warning_saved;
  table->auto_increment_field_not_null= FALSE;
  DBUG_RETURN(TRUE);
}


String *Item_direct_view_ref::str_result(String* tmp)
{
  tmp=(*ref)->str_result(tmp);
  null_value=(*ref)->null_value;
  return tmp;
}


Item* Item_ref::compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
                        Item_transformer transformer, uchar *arg_t)
{
  /* Analyze this Item object. */
  if (!(this->*analyzer)(arg_p))
    return NULL;

  /* Compile the Item we are referencing. */
  DBUG_ASSERT((*ref) != NULL);
  if (*arg_p)
  {
    uchar *arg_v= *arg_p;
    Item *new_item= (*ref)->compile(thd, analyzer, &arg_v, transformer, arg_t);
    if (new_item && *ref != new_item)
      thd->change_item_tree(ref, new_item);
  }

  /* Transform this Item object. */
  return (this->*transformer)(thd, arg_t);
}


void Item_field::save_org_in_field(Field *to,
                                   fast_field_copier fast_field_copier_func)
{
  DBUG_ENTER("Item_field::save_org_in_field");
  DBUG_PRINT("enter", ("setup: %p  data: %p",
                       to, fast_field_copier_func));
  if (fast_field_copier_func)
  {
    if (field->is_null())
    {
      null_value= TRUE;
      set_field_to_null_with_conversions(to, TRUE);
      DBUG_VOID_RETURN;
    }
    to->set_notnull();
    if (to == field)
    {
      null_value= 0;
      DBUG_VOID_RETURN;
    }
    (*fast_field_copier_func)(to, field);
  }
  else
    save_field_in_field(field, &null_value, to, TRUE);
  DBUG_VOID_RETURN;
}


bool Item::cache_const_expr_analyzer(uchar **arg)
{
  bool *cache_flag= (bool*)*arg;
  if (!*cache_flag)
  {
    Item *item= real_item();
    /*
      Cache constant items unless it's a basic constant, constant field or
      a subselect (they use their own cache).
    */
    if (const_item() &&
        !(basic_const_item() || item->basic_const_item() ||
          item->type() == Item::NULL_ITEM || /* Item_name_const hack */
          item->type() == Item::FIELD_ITEM ||
          item->type() == SUBSELECT_ITEM ||
          item->type() == CACHE_ITEM ||
           /*
             Do not cache GET_USER_VAR() function as its const_item() may
             return TRUE for the current thread but it still may change
             during the execution.
           */
          (item->type() == Item::FUNC_ITEM &&
           ((Item_func*)item)->functype() == Item_func::GUSERVAR_FUNC)))
      *cache_flag= TRUE;
    return TRUE;
  }
  return FALSE;
}


bool Item::get_temporal_with_sql_mode(MYSQL_TIME *ltime)
{
  return get_date(ltime, field_type() == MYSQL_TYPE_TIME
                          ? TIME_TIME_ONLY
                          : sql_mode_for_dates(current_thd));
}


const TABLE_SHARE *Item::field_table_or_null()
{
  if (real_item()->type() != Item::FIELD_ITEM)
    return NULL;

  return ((Item_field *) this)->field->table->s;
}


bool Item_param::can_return_value() const
{
  // There's no "default". See comments in Item_param::save_in_field().
  switch (state) {
  case SHORT_DATA_VALUE:
  case LONG_DATA_VALUE:
    return true;
  case IGNORE_VALUE:
  case DEFAULT_VALUE:
    invalid_default_param();
    // fall through
  case NULL_VALUE:
    return false;
  case NO_VALUE:
    DBUG_ASSERT(0); // Should not be possible
    return false;
  }
  DBUG_ASSERT(0); // Garbage
  return false;
}


static bool check_vers_constants(THD *thd, partition_info *part_info)
{
  uint hist_parts= part_info->num_parts - 1;
  Vers_part_info *vers_info= part_info->vers_info;
  vers_info->hist_part= part_info->partitions.head();
  vers_info->now_part= part_info->partitions.elem(hist_parts);

  if (!vers_info->interval.is_set())
    return 0;

  part_info->range_int_array=
    (longlong*) thd->alloc(part_info->num_parts * sizeof(longlong));

  MYSQL_TIME ltime;
  List_iterator<partition_element> it(part_info->partitions);
  partition_element *el;
  my_tz_OFFSET0->gmt_sec_to_TIME(&ltime, vers_info->interval.start);
  while ((el= it++)->id < hist_parts)
  {
    if (date_add_interval(&ltime, vers_info->interval.type,
                          vers_info->interval.step))
      goto err;
    uint error= 0;
    part_info->range_int_array[el->id]= el->range_value=
      my_tz_OFFSET0->TIME_to_gmt_sec(&ltime, &error);
    if (error)
      goto err;
    if (vers_info->hist_part->range_value <= thd->query_start())
      vers_info->hist_part= el;
  }
  DBUG_ASSERT(el == vers_info->now_part);
  el->max_value= true;
  part_info->range_int_array[el->id]= el->range_value= LONGLONG_MAX;
  return 0;
err:
  my_error(ER_DATA_OUT_OF_RANGE, MYF(0), "TIMESTAMP", "INTERVAL");
  return 1;
}


int get_partition_id_list_col(partition_info *part_info,
                              uint32 *part_id,
                              longlong *func_value)
{
  part_column_list_val *list_col_array= part_info->list_col_array;
  uint num_columns= part_info->part_field_list.elements;
  int list_index, cmp;
  int min_list_index= 0;
  int max_list_index= part_info->num_list_values - 1;
  DBUG_ENTER("get_partition_id_list_col");

  while (max_list_index >= min_list_index)
  {
    list_index= (max_list_index + min_list_index) >> 1;
    cmp= cmp_rec_and_tuple(list_col_array + list_index*num_columns,
                          num_columns);
    if (cmp > 0)
      min_list_index= list_index + 1;
    else if (cmp < 0)
    {
      if (!list_index)
        goto notfound;
      max_list_index= list_index - 1;
    }
    else
    {
      *part_id= (uint32)list_col_array[list_index*num_columns].partition_id;
      DBUG_RETURN(0);
    }
  }
notfound:
  if (part_info->defined_max_value)
  {
    *part_id= part_info->default_partition_id;
    DBUG_RETURN(0);
  }
  *part_id= 0;
  DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND);
}


Item_uint::Item_uint(THD *thd, const char *str_arg, longlong i, uint length):
  Item_int(thd, str_arg, i, length)
{
  unsigned_flag= 1;
}


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;
  List<Natural_join_column> *non_join_columns;
  List<Natural_join_column> *join_columns;
  DBUG_ENTER("store_natural_using_join_columns");

  DBUG_ASSERT(!natural_using_join->join_columns);

  arena= thd->activate_stmt_arena_if_needed(&backup);

  if (!(non_join_columns= new List<Natural_join_column>) ||
      !(join_columns= new List<Natural_join_column>))
    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())
  {
    nj_col_1= it_1.get_natural_column_ref();
    if (nj_col_1->is_common)
    {
      join_columns->push_back(nj_col_1, thd->mem_root);
      /* 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, thd->mem_root);
  }

  /*
    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++))
    {
      const char *using_field_name_ptr= using_field_name->c_ptr();
      List_iterator_fast<Natural_join_column>
        it(*join_columns);
      Natural_join_column *common_field;

      for (;;)
      {
        /* 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;
        }
        if (!my_strcasecmp(system_charset_info,
                           common_field->name()->str, using_field_name_ptr))
          break;                                // Found match
      }
    }
  }

  /* 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())
  {
    nj_col_2= it_2.get_natural_column_ref();
    if (!nj_col_2->is_common)
      non_join_columns->push_back(nj_col_2, thd->mem_root);
    else
    {
      /* Reset the common columns for the next call to mark_common_columns. */
      nj_col_2->is_common= FALSE;
    }
  }

  if (non_join_columns->elements > 0)
    join_columns->append(non_join_columns);
  natural_using_join->join_columns= join_columns;
  natural_using_join->is_join_columns_complete= TRUE;

  result= FALSE;

  if (arena)
    thd->restore_active_arena(arena, &backup);
  DBUG_RETURN(result);

err:
  /*
     Actually we failed to build join columns list, so we have to
     clear it to avoid problems with half-build join on next run.
     The list was created in mark_common_columns().
   */
  table_ref_1->remove_join_columns();
  table_ref_2->remove_join_columns();

  if (arena)
    thd->restore_active_arena(arena, &backup);
  DBUG_RETURN(TRUE);
}


Item* Item_ref::transform(THD *thd, Item_transformer transformer, uchar *arg)
{
  DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());
  DBUG_ASSERT((*ref) != NULL);

  /* Transform the object we are referencing. */
  Item *new_item= (*ref)->transform(thd, transformer, arg);
  if (!new_item)
    return NULL;

  /*
    THD::change_item_tree() should be called only if the tree was
    really transformed, i.e. when a new item has been created.
    Otherwise we'll be allocating a lot of unnecessary memory for
    change records at each execution.
  */
  if (*ref != new_item)
    thd->change_item_tree(ref, new_item);

  /* Transform the item ref object. */
  return (this->*transformer)(thd, arg);
}


Item *Item_direct_view_ref::propagate_equal_fields(THD *thd,
                                                   const Context &ctx,
                                                   COND_EQUAL *cond)
{
  Item *field_item= real_item();
  if (field_item->type() != FIELD_ITEM)
    return this;
  Item *item= field_item->propagate_equal_fields(thd, ctx, cond);
  set_item_equal(field_item->get_item_equal());
  field_item->set_item_equal(NULL);
  if (item != field_item)
    return item;
  return this;
}


bool TABLE_LIST::process_index_hints(TABLE *tbl)
{
  /* initialize the result variables */
  tbl->keys_in_use_for_query= tbl->keys_in_use_for_group_by=
    tbl->keys_in_use_for_order_by= tbl->s->keys_in_use;

  /* index hint list processing */
  if (index_hints)
  {
    key_map index_join[INDEX_HINT_FORCE + 1];
    key_map index_order[INDEX_HINT_FORCE + 1];
    key_map index_group[INDEX_HINT_FORCE + 1];
    Index_hint *hint;
    int type;
    bool have_empty_use_join= FALSE, have_empty_use_order= FALSE,
         have_empty_use_group= FALSE;
    List_iterator <Index_hint> iter(*index_hints);

    /* initialize temporary variables used to collect hints of each kind */
    for (type= INDEX_HINT_IGNORE; type <= INDEX_HINT_FORCE; type++)
    {
      index_join[type].clear_all();
      index_order[type].clear_all();
      index_group[type].clear_all();
    }

    /* iterate over the hints list */
    while ((hint= iter++))
    {
      uint pos;

      /* process empty USE INDEX () */
      if (hint->type == INDEX_HINT_USE && !hint->key_name.str)
      {
        if (hint->clause & INDEX_HINT_MASK_JOIN)
        {
          index_join[hint->type].clear_all();
          have_empty_use_join= TRUE;
        }
        if (hint->clause & INDEX_HINT_MASK_ORDER)
        {
          index_order[hint->type].clear_all();
          have_empty_use_order= TRUE;
        }
        if (hint->clause & INDEX_HINT_MASK_GROUP)
        {
          index_group[hint->type].clear_all();
          have_empty_use_group= TRUE;
        }
        continue;
      }

      /*
        Check if an index with the given name exists and get his offset in
        the keys bitmask for the table
      */
      if (tbl->s->keynames.type_names == 0 ||
          (pos= find_type(&tbl->s->keynames, hint->key_name.str,
                          hint->key_name.length, 1)) <= 0)
      {
        my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), hint->key_name.str, alias.str);
        return 1;
      }

      pos--;

      /* add to the appropriate clause mask */
      if (hint->clause & INDEX_HINT_MASK_JOIN)
        index_join[hint->type].set_bit (pos);
      if (hint->clause & INDEX_HINT_MASK_ORDER)
        index_order[hint->type].set_bit (pos);
      if (hint->clause & INDEX_HINT_MASK_GROUP)
        index_group[hint->type].set_bit (pos);
    }

    /* cannot mix USE INDEX and FORCE INDEX */
    if ((!index_join[INDEX_HINT_FORCE].is_clear_all() ||
         !index_order[INDEX_HINT_FORCE].is_clear_all() ||
         !index_group[INDEX_HINT_FORCE].is_clear_all()) &&
        (!index_join[INDEX_HINT_USE].is_clear_all() ||  have_empty_use_join ||
         !index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order ||
         !index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group))
    {
      my_error(ER_WRONG_USAGE, MYF(0), index_hint_type_name[INDEX_HINT_USE],
               index_hint_type_name[INDEX_HINT_FORCE]);
      return 1;
    }

    /* process FORCE INDEX as USE INDEX with a flag */
    if (!index_order[INDEX_HINT_FORCE].is_clear_all())
    {
      tbl->force_index_order= TRUE;
      index_order[INDEX_HINT_USE].merge(index_order[INDEX_HINT_FORCE]);
    }

    if (!index_group[INDEX_HINT_FORCE].is_clear_all())
    {
      tbl->force_index_group= TRUE;
      index_group[INDEX_HINT_USE].merge(index_group[INDEX_HINT_FORCE]);
    }

    /*
      TODO: get rid of tbl->force_index (on if any FORCE INDEX is specified)
      and create tbl->force_index_join instead.
      Then use the correct force_index_XX instead of the global one.
    */
    if (!index_join[INDEX_HINT_FORCE].is_clear_all() ||
        tbl->force_index_group || tbl->force_index_order)
    {
      tbl->force_index= TRUE;
      index_join[INDEX_HINT_USE].merge(index_join[INDEX_HINT_FORCE]);
    }

    /* apply USE INDEX */
    if (!index_join[INDEX_HINT_USE].is_clear_all() || have_empty_use_join)
      tbl->keys_in_use_for_query.intersect(index_join[INDEX_HINT_USE]);
    if (!index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order)
      tbl->keys_in_use_for_order_by.intersect (index_order[INDEX_HINT_USE]);
    if (!index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group)
      tbl->keys_in_use_for_group_by.intersect (index_group[INDEX_HINT_USE]);

    /* apply IGNORE INDEX */
    tbl->keys_in_use_for_query.subtract (index_join[INDEX_HINT_IGNORE]);
    tbl->keys_in_use_for_order_by.subtract (index_order[INDEX_HINT_IGNORE]);
    tbl->keys_in_use_for_group_by.subtract (index_group[INDEX_HINT_IGNORE]);
  }

  /* make sure covering_keys don't include indexes disabled with a hint */
  tbl->covering_keys.intersect(tbl->keys_in_use_for_query);
  return 0;
}


void prune_partition_set(const TABLE *table, part_id_range *part_spec)
{
  int last_partition= -1;
  uint i;
  partition_info *part_info= table->part_info;

  DBUG_ENTER("prune_partition_set");
  for (i= part_spec->start_part; i <= part_spec->end_part; i++)
  {
    if (bitmap_is_set(&(part_info->read_partitions), i))
    {
      DBUG_PRINT("info", ("Partition %d is set", i));
      if (last_partition == -1)
        /* First partition found in set and pruned bitmap */
        part_spec->start_part= i;
      last_partition= i;
    }
  }
  if (last_partition == -1)
    /* No partition found in pruned bitmap */
    part_spec->start_part= part_spec->end_part + 1;
  else //if (last_partition != -1)
    part_spec->end_part= last_partition;

  DBUG_VOID_RETURN;
}


void Item_hex_constant::hex_string_init(THD *thd, const char *str, size_t str_length)
{
  max_length=(uint)((str_length+1)/2);
  char *ptr=(char*) thd->alloc(max_length+1);
  if (!ptr)
  {
    str_value.set("", 0, &my_charset_bin);
    return;
  }
  str_value.set(ptr,max_length,&my_charset_bin);
  char *end=ptr+max_length;
  if (max_length*2 != str_length)
    *ptr++=char_val(*str++);			// Not even, assume 0 prefix
  while (ptr != end)
  {
    *ptr++= (char) (char_val(str[0])*16+char_val(str[1]));
    str+=2;
  }
  *ptr=0;					// Keep purify happy
  collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
  fixed= 1;
  unsigned_flag= 1;
}


bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference)
{
  /* view fild reference must be defined */
  DBUG_ASSERT(*ref);
  /* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */
  if ((*ref)->fixed)
  {
    Item *ref_item= (*ref)->real_item();
    if (ref_item->type() == Item::FIELD_ITEM)
    {
      /*
        In some cases we need to update table read set(see bug#47150).
        If ref item is FIELD_ITEM and fixed then field and table
        have proper values. So we can use them for update.
      */
      Field *fld= ((Item_field*) ref_item)->field;
      DBUG_ASSERT(fld && fld->table);
      if (thd->column_usage == MARK_COLUMNS_READ)
        bitmap_set_bit(fld->table->read_set, fld->field_index);
    }
  }
  else if ((*ref)->fix_fields_if_needed(thd, ref))
    return TRUE;

  if (Item_direct_ref::fix_fields(thd, reference))
    return TRUE;
  if (view->table && view->table->maybe_null)
    maybe_null= TRUE;
  set_null_ref_table();
  return FALSE;
}


Item_field *Item_splocal::get_variable(sp_rcontext *ctx) const
{
  return get_rcontext(ctx)->get_variable(m_var_idx);
}


bool Item_field::collect_item_field_processor(void *arg)
{
  DBUG_ENTER("Item_field::collect_item_field_processor");
  DBUG_PRINT("info", ("%s", field->field_name.str ?
                      field->field_name.str : "noname"));
  List<Item_field> *item_list= (List<Item_field>*) arg;
  List_iterator<Item_field> item_list_it(*item_list);
  Item_field *curr_item;
  while ((curr_item= item_list_it++))
  {
    if (curr_item->eq(this, 1))
      DBUG_RETURN(FALSE); /* Already in the set. */
  }
  item_list->push_back(this);
  DBUG_RETURN(FALSE);
}


bool Item_param::set_str(const char *str, ulong length,
                         CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
  DBUG_ENTER("Item_param::set_str");
  DBUG_ASSERT(value.type_handler()->cmp_type() == STRING_RESULT);
  /*
    Assign string with no conversion: data is converted only after it's
    been written to the binary log.
  */
  uint dummy_errors;
  if (unlikely(value.m_string.copy(str, length, fromcs, tocs, &dummy_errors)))
    DBUG_RETURN(TRUE);
  /*
    Set str_value_ptr to make sure it's in sync with str_value.
    This is needed in case if we're called from Item_param::set_value(),
    from the code responsible for setting OUT parameters in
    sp_head::execute_procedure(). This makes sure that
    Protocol_binary::send_out_parameters() later gets a valid value
    from Item_param::val_str().
    Note, for IN parameters, Item_param::convert_str_value() will be called
    later, which will convert the value from the client character set to the
    connection character set, and will reset both str_value and str_value_ptr.
  */
  value.m_string_ptr.set(value.m_string.ptr(),
                         value.m_string.length(),
                         value.m_string.charset());
  state= SHORT_DATA_VALUE;
  collation.set(tocs, DERIVATION_COERCIBLE);
  max_length= length;
  maybe_null= 0;
  null_value= 0;
  /* max_length and decimals are set after charset conversion */
  /* sic: str may be not null-terminated, don't add DBUG_PRINT here */
  fix_type(Item::STRING_ITEM);
  DBUG_RETURN(FALSE);
}


Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg,
                       const LEX_CSTRING *field_name_arg)
  :Item_result_field(thd), orig_db_name(NullS),
   orig_table_name(view_arg->table_name.str),
   orig_field_name(*field_name_arg),
   context(&view_arg->view->select_lex.context),
   db_name(NullS), table_name(view_arg->alias.str),
   field_name(*field_name_arg),
   alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
   cached_table(NULL), depended_from(NULL), can_be_depended(TRUE)
{
  name= *field_name_arg;
}


Object_creation_ctx *Object_creation_ctx::set_n_backup(THD *thd)
{
  Object_creation_ctx *backup_ctx;
  DBUG_ENTER("Object_creation_ctx::set_n_backup");

  backup_ctx= create_backup_ctx(thd);
  change_env(thd);

  DBUG_RETURN(backup_ctx);
}


Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg)
{
  SELECT_LEX *select= (SELECT_LEX*)select_arg;
  DBUG_ASSERT(fixed);

  if (field->table != select->context.table_list->table &&
      type() != Item::TRIGGER_FIELD_ITEM)
  {
    List<Item> *all_fields= &select->join->all_fields;
    Ref_ptr_array &ref_pointer_array= select->ref_pointer_array;
    int el= all_fields->elements;
    Item_ref *ref;

    ref_pointer_array[el]= (Item*)this;
    all_fields->push_front((Item*)this, thd->mem_root);
    ref= new (thd->mem_root)
      Item_ref(thd, &select->context, &ref_pointer_array[el],
               table_name, &field_name);
    return ref;
  }
  return this;
}


int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
{
  calculate();
  return Item_field::save_in_field(field_arg, no_conversions);
}


Item_decimal::Item_decimal(THD *thd, longlong val, bool unsig):
  Item_num(thd)
{
  int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value);
  decimals= (uint8) decimal_value.frac;
  fixed= 1;
  max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
                                                           decimals,
                                                           decimals,
                                                           unsigned_flag);
}


bool TABLE::add_tmp_key(uint key, uint key_parts,
                        uint (*next_field_no) (uchar *), uchar *arg,
                        bool unique)
{
  DBUG_ASSERT(key < max_keys);

  char buf[NAME_CHAR_LEN];
  KEY* keyinfo;
  Field **reg_field;
  uint i;

  bool key_start= TRUE;
  KEY_PART_INFO* key_part_info=
      (KEY_PART_INFO*) alloc_root(&mem_root, sizeof(KEY_PART_INFO)*key_parts);
  if (!key_part_info)
    return TRUE;
  keyinfo= key_info + key;
  keyinfo->key_part= key_part_info;
  keyinfo->usable_key_parts= keyinfo->user_defined_key_parts = key_parts;
  keyinfo->ext_key_parts= keyinfo->user_defined_key_parts;
  keyinfo->key_length=0;
  keyinfo->algorithm= HA_KEY_ALG_UNDEF;
  keyinfo->flags= HA_GENERATED_KEY;
  keyinfo->ext_key_flags= keyinfo->flags;
  keyinfo->is_statistics_from_stat_tables= FALSE;
  if (unique)
    keyinfo->flags|= HA_NOSAME;
  sprintf(buf, "key%i", key);
  keyinfo->name.length= strlen(buf);
  if (!(keyinfo->name.str= strmake_root(&mem_root, buf, keyinfo->name.length)))
    return TRUE;
  keyinfo->rec_per_key= (ulong*) alloc_root(&mem_root,
                                            sizeof(ulong)*key_parts);
  if (!keyinfo->rec_per_key)
    return TRUE;
  bzero(keyinfo->rec_per_key, sizeof(ulong)*key_parts);
  keyinfo->read_stats= NULL;
  keyinfo->collected_stats= NULL;

  for (i= 0; i < key_parts; i++)
  {
    uint fld_idx= next_field_no(arg);
    reg_field= field + fld_idx;
    if (key_start)
      (*reg_field)->key_start.set_bit(key);
    (*reg_field)->part_of_key.set_bit(key);
    create_key_part_by_field(key_part_info, *reg_field, fld_idx+1);
    keyinfo->key_length += key_part_info->store_length;
    (*reg_field)->flags|= PART_KEY_FLAG;
    key_start= FALSE;
    key_part_info++;
  }

  /*
    For the case when there is a derived table that would give distinct rows,
    the index statistics are passed to the join optimizer to tell that a ref
    access to all the fields of the derived table will produce only one row.
  */

  st_select_lex_unit* derived= pos_in_table_list ?
                               pos_in_table_list->derived: NULL;
  if (derived)
  {
    st_select_lex* first= derived->first_select();
    uint select_list_items= first->get_item_list()->elements;
    if (key_parts == select_list_items)
    {
      if ((!first->is_part_of_union() && (first->options & SELECT_DISTINCT)) ||
          derived->check_distinct_in_union())
        keyinfo->rec_per_key[key_parts - 1]= 1;
    }
  }

  set_if_bigger(s->max_key_length, keyinfo->key_length);
  s->keys++;
  return FALSE;
}


Item *Item_cache_time::make_literal(THD *thd)
{
  MYSQL_TIME ltime;
  unpack_time(val_time_packed(), &ltime, MYSQL_TIMESTAMP_TIME);
  return new (thd->mem_root) Item_time_literal(thd, &ltime, decimals);
}


Item *Item_param::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
  /*
    Return "this" if in prepare. result_type may change at execition time,
    to it's possible that the converter will not be needed at all:

    PREPARE stmt FROM 'SELECT * FROM t1 WHERE field = ?';
    SET @arg= 1;
    EXECUTE stmt USING @arg;

    In the above example result_type is STRING_RESULT at prepare time,
    and INT_RESULT at execution time.
  */
  return !const_item() || state == NULL_VALUE ?
         this : const_charset_converter(thd, tocs, true);
}


bool Item_trigger_field::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it)
{
  Item *item= thd->sp_prepare_func_item(it);

  if (!item || fix_fields_if_needed(thd, NULL))
    return true;

  // NOTE: field->table->copy_blobs should be false here, but let's
  // remember the value at runtime to avoid subtle bugs.
  bool copy_blobs_saved= field->table->copy_blobs;

  field->table->copy_blobs= true;

  int err_code= item->save_in_field(field, 0);

  field->table->copy_blobs= copy_blobs_saved;
  field->set_has_explicit_value();

  return err_code < 0;
}


bool Item_field::rename_fields_processor(void *arg)
{
  Item::func_processor_rename *rename= (Item::func_processor_rename*) arg;
  List_iterator<Create_field> def_it(rename->fields);
  Create_field *def;

  while ((def=def_it++))
  {
    if (def->change.str &&
        (!db_name || !db_name[0] ||
         !my_strcasecmp(table_alias_charset, db_name, rename->db_name.str)) &&
        (!table_name || !table_name[0] ||
         !my_strcasecmp(table_alias_charset, table_name, rename->table_name.str)) &&
        !my_strcasecmp(system_charset_info, field_name.str, def->change.str))
    {
      field_name= def->field_name;
      break;
    }
  }
  return 0;
}


LEX_CSTRING *Field_iterator_view::name()
{
  return &ptr->name;
}


resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
{
  Item **group_by_ref= NULL;
  Item **select_ref= NULL;
  ORDER *group_list= select->group_list.first;
  bool ambiguous_fields= FALSE;
  uint counter;
  enum_resolution_type resolution;

  /*
    Search for a column or derived column named as 'ref' in the SELECT
    clause of the current select.
  */
  if (!(select_ref= find_item_in_list(ref, *(select->get_item_list()),
                                      &counter, REPORT_EXCEPT_NOT_FOUND,
                                      &resolution)))
    return NULL; /* Some error occurred. */
  if (resolution == RESOLVED_AGAINST_ALIAS)
    ref->alias_name_used= TRUE;

  /* If this is a non-aggregated field inside HAVING, search in GROUP BY. */
  if (select->having_fix_field && !ref->with_sum_func && group_list)
  {
    group_by_ref= find_field_in_group_list(ref, group_list);

    /* Check if the fields found in SELECT and GROUP BY are the same field. */
    if (group_by_ref && (select_ref != not_found_item) &&
        !((*group_by_ref)->eq(*select_ref, 0)) &&
        (!select->having_fix_field_for_pushed_cond))
    {
      ambiguous_fields= TRUE;
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_NON_UNIQ_ERROR,
                          ER_THD(thd,ER_NON_UNIQ_ERROR), ref->full_name(),
                          thd->where);

    }
  }

  if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY &&
      select->having_fix_field  &&
      select_ref != not_found_item && !group_by_ref &&
      !ref->alias_name_used)
  {
    /*
      Report the error if fields was found only in the SELECT item list and
      the strict mode is enabled.
    */
    my_error(ER_NON_GROUPING_FIELD_USED, MYF(0),
             ref->name.str, "HAVING");
    return NULL;
  }
  if (select_ref != not_found_item || group_by_ref)
  {
    if (select_ref != not_found_item && !ambiguous_fields)
    {
      DBUG_ASSERT(*select_ref != 0);
      if (!select->ref_pointer_array[counter])
      {
        my_error(ER_ILLEGAL_REFERENCE, MYF(0),
                 ref->name.str, "forward reference in item list");
        return NULL;
      }
      DBUG_ASSERT((*select_ref)->fixed);
      return &select->ref_pointer_array[counter];
    }
    if (group_by_ref)
      return group_by_ref;
    DBUG_ASSERT(FALSE);
    return NULL; /* So there is no compiler warning. */
  }

  return (Item**) not_found_item;
}


table_map Item_default_value::used_tables() const
{
  if (!field || !field->default_value)
    return static_cast<table_map>(0);
  if (!field->default_value->expr)           // not fully parsed field
    return static_cast<table_map>(RAND_TABLE_BIT);
  return field->default_value->expr->used_tables();
}


find_field_in_table(THD *thd, TABLE *table, const char *name, size_t length,
                    bool allow_rowid, uint *cached_field_index_ptr)
{
  Field *field;
  uint cached_field_index= *cached_field_index_ptr;
  DBUG_ENTER("find_field_in_table");
  DBUG_PRINT("enter", ("table: '%s', field name: '%s'", table->alias.c_ptr(),
                       name));

  /* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */
  if (cached_field_index < table->s->fields &&
      !my_strcasecmp(system_charset_info,
                     table->field[cached_field_index]->field_name.str, name))
    field= table->field[cached_field_index];
  else
  {
    LEX_CSTRING fname= {name, length};
    field= table->find_field_by_name(&fname);
  }

  if (field)
  {
    if (field->invisible == INVISIBLE_FULL &&
        DBUG_EVALUATE_IF("test_completely_invisible", 0, 1))
      DBUG_RETURN((Field*)0);

    if (field->invisible == INVISIBLE_SYSTEM &&
        thd->column_usage != MARK_COLUMNS_READ &&
        thd->column_usage != COLUMNS_READ)
      DBUG_RETURN((Field*)0);
  }
  else
  {
    if (!allow_rowid ||
        my_strcasecmp(system_charset_info, name, "_rowid") ||
        table->s->rowid_field_offset == 0)
      DBUG_RETURN((Field*) 0);
    field= table->field[table->s->rowid_field_offset-1];
  }
  *cached_field_index_ptr= field->field_index;

  update_field_dependencies(thd, field, table);

  DBUG_RETURN(field);
}


Item* Item::propagate_equal_fields_and_change_item_tree(THD *thd,
                                                        const Context &ctx,
                                                        COND_EQUAL *cond,
                                                        Item **place)
{
  Item *item= propagate_equal_fields(thd, ctx, cond);
  if (item && item != this)
    thd->change_item_tree(place, item);
  return item;
}


bool Item_direct_view_ref::val_bool_result()
{
  bool tmp= (*ref)->val_bool_result();
  null_value=(*ref)->null_value;
  return tmp;
}


enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags)
{
  bool error_given= false;
  File file;
  uchar *buf;
  uchar head[FRM_HEADER_SIZE];
  char	path[FN_REFLEN];
  size_t frmlen, read_length;
  uint length;
  DBUG_ENTER("open_table_def");
  DBUG_PRINT("enter", ("table: '%s'.'%s'  path: '%s'", share->db.str,
                       share->table_name.str, share->normalized_path.str));

  share->error= OPEN_FRM_OPEN_ERROR;

  length=(uint) (strxmov(path, share->normalized_path.str, reg_ext, NullS) -
                 path);
  if (flags & GTS_FORCE_DISCOVERY)
  {
    DBUG_ASSERT(flags & GTS_TABLE);
    DBUG_ASSERT(flags & GTS_USE_DISCOVERY);
    mysql_file_delete_with_symlink(key_file_frm, path, "", MYF(0));
    file= -1;
  }
  else
    file= mysql_file_open(key_file_frm, path, O_RDONLY | O_SHARE, MYF(0));

  if (file < 0)
  {
    if ((flags & GTS_TABLE) && (flags & GTS_USE_DISCOVERY))
    {
      ha_discover_table(thd, share);
      error_given= true;
    }
    goto err_not_open;
  }

  if (mysql_file_read(file, head, sizeof(head), MYF(MY_NABP)))
  {
    share->error = my_errno == HA_ERR_FILE_TOO_SHORT
                      ? OPEN_FRM_CORRUPTED : OPEN_FRM_READ_ERROR;
    goto err;
  }

  if (memcmp(head, STRING_WITH_LEN("TYPE=VIEW\n")) == 0)
  {
    share->is_view= 1;
    if (flags & GTS_VIEW)
    {
      LEX_CSTRING pathstr= { path, length };
      /*
        Create view file parser and hold it in TABLE_SHARE member
        view_def.
      */
      share->view_def= sql_parse_prepare(&pathstr, &share->mem_root, true);
      if (!share->view_def)
        share->error= OPEN_FRM_ERROR_ALREADY_ISSUED;
      else
        share->error= OPEN_FRM_OK;
    }
    else
      share->error= OPEN_FRM_NOT_A_TABLE;
    goto err;
  }
  if (!is_binary_frm_header(head))
  {
    /* No handling of text based files yet */
    share->error = OPEN_FRM_CORRUPTED;
    goto err;
  }
  if (!(flags & GTS_TABLE))
  {
    share->error = OPEN_FRM_NOT_A_VIEW;
    goto err;
  }

  frmlen= uint4korr(head+10);
  set_if_smaller(frmlen, FRM_MAX_SIZE); // safety

  if (!(buf= (uchar*)my_malloc(frmlen, MYF(MY_THREAD_SPECIFIC|MY_WME))))
    goto err;

  memcpy(buf, head, sizeof(head));

  read_length= mysql_file_read(file, buf + sizeof(head),
                               frmlen - sizeof(head), MYF(MY_WME));
  if (read_length == 0 || read_length == (size_t)-1)
  {
    share->error = OPEN_FRM_READ_ERROR;
    my_free(buf);
    goto err;
  }
  mysql_file_close(file, MYF(MY_WME));

  frmlen= read_length + sizeof(head);

  share->init_from_binary_frm_image(thd, false, buf, frmlen);
  /*
    Don't give any additional errors. If there would be a problem,
    init_from_binary_frm_image would call my_error() itself.
  */
  error_given= true;
  my_free(buf);

  goto err_not_open;

err:
  mysql_file_close(file, MYF(MY_WME));

err_not_open:
  /* Mark that table was created earlier and thus should have been logged */
  share->table_creation_was_logged= 1;

  if (unlikely(share->error && !error_given))
  {
    share->open_errno= my_errno;
    open_table_error(share, share->error, share->open_errno);
  }

  DBUG_RETURN(share->error);
}


int closefrm(TABLE *table)
{
  int error=0;
  DBUG_ENTER("closefrm");
  DBUG_PRINT("enter", ("table: %p", table));

  if (table->db_stat)
    error=table->file->ha_close();
  table->alias.free();
  if (table->expr_arena)
    table->expr_arena->free_items();
  if (table->field)
  {
    for (Field **ptr=table->field ; *ptr ; ptr++)
    {
      delete *ptr;
    }
    table->field= 0;
  }
  delete table->file;
  table->file= 0;				/* For easier errorchecking */
#ifdef WITH_PARTITION_STORAGE_ENGINE
  if (table->part_info)
  {
    /* Allocated through table->mem_root, freed below */
    free_items(table->part_info->item_free_list);
    table->part_info->item_free_list= 0;
    table->part_info= 0;
  }
#endif
  free_root(&table->mem_root, MYF(0));
  DBUG_RETURN(error);
}


bool Item_splocal::check_cols(uint n)
{
  DBUG_ASSERT(m_thd->spcont);
  if (Type_handler_hybrid_field_type::cmp_type() != ROW_RESULT)
    return Item::check_cols(n);

  if (n != this_item()->cols() || n == 1)
  {
    my_error(ER_OPERAND_COLUMNS, MYF(0), n);
    return true;
  }
  return false;
}


void truncate_partition_filename(char *path)
{
  if (path)
  {
    char* last_slash= strrchr(path, FN_LIBCHAR);

    if (!last_slash)
      last_slash= strrchr(path, FN_LIBCHAR2);

    if (last_slash)
    {
      /* Look for a partition-type filename */
      for (char* pound= strchr(last_slash, '#');
           pound; pound = strchr(pound + 1, '#'))
      {
        if ((pound[1] == 'P' || pound[1] == 'p') && pound[2] == '#')
        {
          last_slash[0] = '\0';	/* truncate the file name */
          break;
        }
      }
    }
  }
}


bool TABLE::check_tmp_key(uint key, uint key_parts,
                          uint (*next_field_no) (uchar *), uchar *arg)
{
  Field **reg_field;
  uint i;
  uint key_len= 0;

  for (i= 0; i < key_parts; i++)
  {
    uint fld_idx= next_field_no(arg);
    reg_field= field + fld_idx;
    if ((*reg_field)->type() == MYSQL_TYPE_BLOB)
      return FALSE;
    uint fld_store_len= (uint16) (*reg_field)->key_length();
    if ((*reg_field)->real_maybe_null())
      fld_store_len+= HA_KEY_NULL_LENGTH;
    if ((*reg_field)->real_type() == MYSQL_TYPE_VARCHAR ||
        (*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
      fld_store_len+= HA_KEY_BLOB_LENGTH;
    key_len+= fld_store_len;
  }
  /*
    We use MI_MAX_KEY_LENGTH (myisam's default) below because it is
    smaller than MAX_KEY_LENGTH (heap's default) and it's unknown whether
    myisam or heap will be used for the temporary table.
  */
  return key_len <= MI_MAX_KEY_LENGTH;
}


uint size_of() const { return sizeof(*this); }


bool Field_medium::send_binary(Protocol *protocol)
{
  ASSERT_COLUMN_MARKED_FOR_READ;
  return protocol->store_long(Field_medium::val_int());
}


int Field_str::store(double nr)
{
  ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
  char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
  uint local_char_length= MY_MIN(sizeof(buff),
                                 field_length / field_charset->mbmaxlen);
  size_t length= 0;
  my_bool error= (local_char_length == 0);

  // my_gcvt() requires width > 0, and we may have a CHAR(0) column.
  if (likely(!error))
    length= my_gcvt(nr, MY_GCVT_ARG_DOUBLE, local_char_length, buff, &error);

  if (unlikely(error))
  {
    if (get_thd()->abort_on_warning)
      set_warning(ER_DATA_TOO_LONG, 1);
    else
      set_warning(WARN_DATA_TRUNCATED, 1);
  }
  return store(buff, (uint)length, &my_charset_numeric);
}


uint Field_varstring::is_equal(Create_field *new_field)
{
  if (new_field->type_handler() == type_handler() &&
      new_field->charset == field_charset &&
      !new_field->compression_method() == !compression_method())
  {
    if (new_field->length == field_length)
      return IS_EQUAL_YES;
    if (new_field->length > field_length &&
	((new_field->length <= 255 && field_length <= 255) ||
	 (new_field->length > 255 && field_length > 255)))
      return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer variable length
  }
  return IS_EQUAL_NO;
}


int Field_time::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
  int32 a,b;
  a=(int32) sint3korr(a_ptr);
  b=(int32) sint3korr(b_ptr);
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}


int save_in_field(Field *to) { return to->store(val_real()); }


bool str_needs_quotes() { return TRUE; }


String *Field_year::val_str(String *val_buffer,
			    String *val_ptr __attribute__((unused)))
{
  DBUG_ASSERT(field_length < 5);
  val_buffer->alloc(5);
  val_buffer->length(field_length);
  char *to=(char*) val_buffer->ptr();
  sprintf(to,field_length == 2 ? "%02d" : "%04d",(int) Field_year::val_int());
  val_buffer->set_charset(&my_charset_numeric);
  return val_buffer;
}


uint Field_varstring::get_key_image(uchar *buff, uint length,
                                    imagetype type_arg)
{
  String val;
  uint local_char_length;

  MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->read_set);
  val_str(&val, &val);
  dbug_tmp_restore_column_map(&table->read_set, old_map);

  local_char_length= val.charpos(length / field_charset->mbmaxlen);
  if (local_char_length < val.length())
    val.length(local_char_length);
  /* Key is always stored with 2 bytes */
  int2store(buff, val.length());
  memcpy(buff + HA_KEY_BLOB_LENGTH, val.ptr(), val.length());
  if (val.length() < length)
  {
    /*
      Must clear this as we do a memcmp in opt_range.cc to detect
      identical keys
    */
    memset(buff + HA_KEY_BLOB_LENGTH + val.length(), 0, length - val.length());
  }
  return HA_KEY_BLOB_LENGTH + val.length();
}


longlong Field_float::val_int(void)
{
  float j;
  float4get(j,ptr);
  return Converter_double_to_longlong(j, false).result();
}


  virtual const uchar *unpack(uchar* to, const uchar *from,
                              const uchar *from_end, uint param_data)
  {
    if (from == from_end)
      return 0;
    *to= *from;
    return from + 1;
  }


virtual uint32 pack_length_in_rec() const { return pack_length(); }


  virtual int cmp_binary_offset(uint row_offset)
  { return cmp_binary(ptr, ptr+row_offset); };


bool Field_newdate::send_binary(Protocol *protocol)
{
  MYSQL_TIME tm;
  Field_newdate::get_date(&tm,0);
  return protocol->store_date(&tm);
}


String *Field_float::val_str(String *val_buffer,
			     String *val_ptr __attribute__((unused)))
{
  ASSERT_COLUMN_MARKED_FOR_READ;
  DBUG_ASSERT(!zerofill || field_length <= MAX_FIELD_CHARLENGTH);

  if (Float(ptr).to_string(val_buffer, dec))
  {
    my_error(ER_OUT_OF_RESOURCES, MYF(0));
    return val_buffer;
  }

  if (zerofill)
    prepend_zeros(val_buffer);
  return val_buffer;
}


  virtual uint32 max_data_length() const
  {
    return (uint32) (((ulonglong) 1 << (packlength*8)) -1);
  }


  Spvar_definition *find_row_field_by_name(const LEX_CSTRING *name, uint *offset) const
  {
    // Cast-off the "const" qualifier
    List_iterator<Spvar_definition> it(*((List<Spvar_definition>*)this));
    Spvar_definition *def;
    for (*offset= 0; (def= it++); (*offset)++)
    {
      if (eq_name(def, name))
        return def;
    }
    return 0;
  }


  virtual ulonglong get_max_int_value() const
  {
    DBUG_ASSERT(false);
    return 0ULL;
  }


  const Type_handler *type_handler() const
  {
    return Type_handler_hybrid_field_type::type_handler();
  }


  int save_in_field(Field *to)
  {
    my_decimal buff;
    return to->store_decimal(val_decimal(&buff));
  }


enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }


const Type_handler *type_handler() const { return &type_handler_tiny; }


  Item_result result_type () const
  {
    return type_handler()->result_type();
  }


int Field_geom::store(const char *from, size_t length, CHARSET_INFO *cs)
{
  if (!length)
    bzero(ptr, Field_blob::pack_length());
  else
  {
    if (from == Geometry::bad_geometry_data.ptr())
      goto err;
    // Check given WKB
    uint32 wkb_type;
    if (length < SRID_SIZE + WKB_HEADER_SIZE + 4)
      goto err;
    wkb_type= uint4korr(from + SRID_SIZE + 1);
    if (wkb_type < (uint32) Geometry::wkb_point ||
	wkb_type > (uint32) Geometry::wkb_last)
      goto err;

    if (geom_type != Field::GEOM_GEOMETRY &&
        geom_type != Field::GEOM_GEOMETRYCOLLECTION &&
        (uint32) geom_type != wkb_type)
    {
      const char *db= table->s->db.str;
      const char *tab_name= table->s->table_name.str;
      Geometry_buffer buffer;
      Geometry *geom= NULL;
      String wkt;
      const char *dummy;

      if (!db)
        db= "";
      if (!tab_name)
        tab_name= "";
      wkt.set_charset(&my_charset_latin1);
      if (!(geom= Geometry::construct(&buffer, from, uint32(length))) ||
          geom->as_wkt(&wkt, &dummy))
        goto err;

      my_error(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, MYF(0),
               Geometry::ci_collection[geom_type]->m_name.str,
               wkt.c_ptr_safe(), db, tab_name, field_name.str,
               (ulong) table->in_use->get_stmt_da()->
               current_row_for_warning());

      goto err_exit;
    }

    Field_blob::store_length(length);
    if ((table->copy_blobs || length <= MAX_FIELD_WIDTH) &&
        from != value.ptr())
    {						// Must make a copy
      value.copy(from, length, cs);
      from= value.ptr();
    }
    bmove(ptr + packlength, &from, sizeof(char*));
  }
  return 0;

err:
  my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
             ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
err_exit:
  bzero(ptr, Field_blob::pack_length());
  return -1;
}


enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }


  const uchar *unpack_int32(uchar* to, const uchar *from, const uchar *from_end)
  { return unpack_int(to, from, from_end, 4); }


  uchar *pack(uchar* to, const uchar *from,
              uint max_length __attribute__((unused)))
  {
    return pack_int32(to, from);
  }


int Field_timestamp::store(longlong nr, bool unsigned_val)
{
  MYSQL_TIME l_time;
  int error;
  ErrConvInteger str(nr, unsigned_val);
  THD *thd= get_thd();

  longlong tmp= number_to_datetime(nr, 0, &l_time, sql_mode_for_timestamp(thd),
                                   &error);
  return store_TIME_with_warning(thd, &l_time, &str, error, tmp != -1);
}