table_map used_tables() const { return used_tables_cache; }


  void fix_from_value(Derivation dv, const Metadata metadata)
  {
    fix_charset_and_length_from_str_value(dv, metadata);
    // it is constant => can be used without fix_fields (and frequently used)
    fixed= 1;
  }

MDEV-25635 Assertion failure when pushing from HAVING into WHERE of view

This bug could manifest itself after pushing a where condition over a
mergeable derived table / view / CTE DT into a grouping view / derived
table / CTE V whose item list contained set functions with constant
arguments such as MIN(2), SUM(1) etc. In such cases the field references
used in the condition pushed into the view V that correspond set functions
are wrapped into Item_direct_view_ref wrappers. Due to a wrong implementation
of the virtual method const_item() for the class Item_direct_view_ref the
wrapped set functions with constant arguments could be erroneously taken
for constant items. This could lead to a wrong result set returned by the
main select query in 10.2. In 10.4 where a possibility of pushing condition
from HAVING into WHERE had been added this could cause a crash.

Approved by Sergey Petrunya <sergey.petrunya@mariadb.com>


  Item_args(THD *thd, List<Item> &list)
  {
    set_arguments(thd, list);
  }


bool vcol_assignment_allowed_value() const { return arg == NULL; }


Item_uint(THD *thd, ulonglong i): Item_int(thd, i, 10) {}


  bool cleanup_excluding_const_fields_processor(void *arg)
  {
    Item *item= real_item();
    if (item && item->type() == FIELD_ITEM &&
        ((Item_field *) item)->field && item->const_item())
      return 0;
    return cleanup_processor(arg);
  }


  void save_org_in_field(Field *field,
                         fast_field_copier data __attribute__ ((__unused__)))
  {
    if (check_null_ref())
      field->set_null();
    else
      Item_direct_ref::save_val(field);
  }


  int sortcmp(const String *s, const String *t) const
  {
    return collation->coll->strnncollsp(collation,
                                        (uchar *) s->ptr(), s->length(),
                                        (uchar *) t->ptr(), t->length());
  }


  Cached_item_field(THD *thd, Field *arg_field): field(arg_field)
  {
    field= arg_field;
    /* TODO: take the memory allocation below out of the constructor. */
    buff= (uchar*) thd_calloc(thd, length= field->pack_length());
  }


virtual Item_equal *get_item_equal() { return NULL; }


  Item_hex_constant(THD *thd): Item_basic_constant(thd)
  {
    hex_string_init(thd, "", 0);
  }


  void no_rows_in_result()
  {
    (*ref)->no_rows_in_result();
  }


  enum_field_types odbc_temporal_literal_type(const LEX_STRING *type_str) const
  {
    /*
      If string is a reasonably short pure ASCII string literal,
      try to parse known ODBC style date, time or timestamp literals,
      e.g:
      SELECT {d'2001-01-01'};
      SELECT {t'10:20:30'};
      SELECT {ts'2001-01-01 10:20:30'};
    */
    if (collation.repertoire == MY_REPERTOIRE_ASCII &&
        str_value.length() < MAX_DATE_STRING_REP_LENGTH * 4)
    {
      if (type_str->length == 1)
      {
        if (type_str->str[0] == 'd')  /* {d'2001-01-01'} */
          return MYSQL_TYPE_DATE;
        else if (type_str->str[0] == 't') /* {t'10:20:30'} */
          return MYSQL_TYPE_TIME;
      }
      else if (type_str->length == 2) /* {ts'2001-01-01 10:20:30'} */
      {
        if (type_str->str[0] == 't' && type_str->str[1] == 's')
          return MYSQL_TYPE_DATETIME;
      }
    }
    return MYSQL_TYPE_STRING; // Not a temporal literal
  }


  Item_string(THD *thd, const char *str, uint length, CHARSET_INFO *cs,
              Derivation dv, uint repertoire): Item_basic_constant(thd)
  {
    str_value.set_or_copy_aligned(str, length, cs);
    fix_and_set_name_from_value(thd, dv, Metadata(&str_value, repertoire));
  }


  Used_tables_and_const_cache()
   :used_tables_cache(0),
    const_item_cache(true)
  { }


virtual bool need_parentheses_in_default() { return false; }


  enum Item_result cmp_type () const
  { return Type_handler_hybrid_field_type::cmp_type(); }


  bool is_basic_value(Type type_arg) const
  {
    return basic_const_item() && type() == type_arg;
  }


virtual bool eval_not_null_tables(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;
  }


  bool const_item() const
  {
    return (*ref)->const_item();
  }


  bool save_in_param(THD *thd, Item_param *param)
  {
    // It should not be possible to have "EXECUTE .. USING DEFAULT(a)"
    DBUG_ASSERT(arg == NULL);
    param->set_default();
    return false;
  }


virtual bool is_bool_type() { return false; }


  Settable_routine_parameter *get_settable_routine_parameter()
  { return this; }


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


  my_decimal *val_decimal(my_decimal *decimal_value)
  {
    // following assert is redundant, because fixed=1 assigned in constructor
    DBUG_ASSERT(fixed == 1);
    ulonglong value= (ulonglong) Item_hex_hybrid::val_int();
    int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value);
    return decimal_value;
  }


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


  void print_value(String *to) const
  {
    str_value.print(to);
  }


  bool str_eq(const String *value,
              const String *other, CHARSET_INFO *cs, bool binary_cmp) const
  {
    return binary_cmp ?
      value->bin_eq(other) :
      collation.collation == cs && value->eq(other, collation.collation);
  }


  Item_string_ascii(THD *thd, const char *str, uint length):
    Item_string(thd, str, length, &my_charset_latin1,
                DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII)
  { }


  Item_static_float_func(THD *thd, const char *str, double val_arg,
                         uint decimal_par, uint length):
    Item_float(thd, NullS, val_arg, decimal_par, length), func_name(str)
  {}


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


Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }


Item_basic_value(THD *thd): Item(thd) {}


  Item_float(THD *thd, const char *str, double val_arg, uint decimal_par,
             uint length): Item_num(thd), value(val_arg)
  {
    presentation= name=(char*) str;
    decimals=(uint8) decimal_par;
    max_length=length;
    fixed= 1;
  }


  bool is_expensive_processor(void *arg)
  {
    DBUG_ASSERT(example);
    if (value_cached)
      return false;
    return example->is_expensive_processor(arg);
  }


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


  virtual bool check_vcol_func_processor(void *arg)
  {
    return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE);
  }


  Item_datetime_literal_for_invalid_dates(THD *thd,
                                          MYSQL_TIME *ltime, uint dec_arg)
   :Item_datetime_literal(thd, ltime, dec_arg) { }


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


  Item* element_index(uint i)
  { return result_type() == ROW_RESULT ? orig_item->element_index(i) : this; }


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


  bool check_vcol_func_processor(void *arg)
  {
    return mark_unsupported_function("name_const()", arg, VCOL_IMPOSSIBLE);
  }


  Item_cache_row(THD *thd):
    Item_cache(thd), values(0), item_count(2),
    save_array(0) {}


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


    bool convert_if_needed(THD *thd, String *str)
    {
      /*
        Check is so simple because all charsets were set up properly
        in setup_one_conversion_function, where typecode of
        placeholder was also taken into account: the variables are different
        here only if conversion is really necessary.
      */
      if (needs_conversion())
        return convert(thd, str);
      str->set_charset(final_character_set_of_str_value);
      return false;
    }


bool register_clone(Item_param *i) { return m_clones.push_back(i); }


Item_iterator_row(Item *base) : base_item(base), current(0) {}


  static Item_cache* get_cache(THD *thd, const Item* item,
                         const Item_result type)
  {
    return get_cache(thd, item, type, item->field_type());
  }


Item_field *field_for_view_update() { return this; }


virtual void get_cache_parameters(List<Item> &parameters) { };


double val_real() { return (double)val_int(); }


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


  Item_ref(THD *thd, Name_resolution_context *context_arg,
           const char *db_arg, const char *table_name_arg,
           const char *field_name_arg):
    Item_ident(thd, context_arg, db_arg, table_name_arg, field_name_arg),
    set_properties_only(0), ref(0), reference_trough_name(1) {}


  const Type_handler  *type_handler() const
  {
    return get_handler_by_field_type(field_type());
  }


  Item_direct_view_ref(THD *thd, Name_resolution_context *context_arg,
                       Item **item,
                       const char *table_name_arg,
                       const char *field_name_arg,
                       TABLE_LIST *view_arg):
    Item_direct_ref(thd, context_arg, item, table_name_arg, field_name_arg),
    item_equal(0), view(view_arg),
    null_ref_table(NULL)
  {
    if (fixed)
      set_null_ref_table();
  }


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


  void used_tables_and_const_cache_update_and_join(Item *item)
  {
    item->update_used_tables();
    used_tables_and_const_cache_join(item);
  }


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


  Item_ref_null_helper(THD *thd, Name_resolution_context *context_arg,
                       Item_in_subselect* master, Item **item,
		       const char *table_name_arg, const char *field_name_arg):
    Item_ref(thd, context_arg, item, table_name_arg, field_name_arg),
    owner(master) {}


Cached_item_item(Item *arg) : item(arg) {}


  Item_iterator_ref_list(List_iterator<Item*> &arg_list):
    list(arg_list) {}


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


Item_basic_constant(THD *thd): Item_basic_value(thd), used_table_map(0) {};


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


  bool has_long_data_value() const
  {
    return state == LONG_DATA_VALUE;
  }


  Item_return_date_time(THD *thd, const char *name_arg, uint length_arg,
                        enum_field_types field_type_arg):
    Item_partition_func_safe_string(thd, name_arg, length_arg, &my_charset_bin),
    date_time_field_type(field_type_arg)
  { decimals= 0; }


  virtual void update_used_tables()
  {
    if (field && field->default_value)
      field->default_value->expr->update_used_tables();
  }


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


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


  virtual longlong val_time_packed()
  {
    MYSQL_TIME ltime;
    uint fuzzydate= TIME_FUZZY_DATES | TIME_INVALID_DATES | TIME_TIME_ONLY;
    return get_date(&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); }


inline void Item_sp_variable::make_field(THD *thd, Send_field *field)
{
  Item *it= this_item();

  if (name)
    it->set_name(thd, name, (uint) strlen(name), system_charset_info);
  else
    it->set_name(thd, m_name.str, (uint) m_name.length, system_charset_info);
  it->make_field(thd, field);
}


  bool check_vcol_func_processor(void *arg)
  {
    return mark_unsupported_function("copy", arg, VCOL_IMPOSSIBLE);
  }


  bool needs_charset_converter(uint32 length, CHARSET_INFO *tocs) const
  {
    /*
      This will return "true" if conversion happens:
      - between two non-binary different character sets
      - from "binary" to "unsafe" character set
        (those that can have non-well-formed string)
      - from "binary" to UCS2-alike character set with mbminlen>1,
        when prefix left-padding is needed for an incomplete character:
        binary 0xFF -> ucs2 0x00FF)
    */
    if (!String::needs_conversion_on_storage(length,
                                             collation.collation, tocs))
      return false;
    /*
      No needs to add converter if an "arg" is NUMERIC or DATETIME
      value (which is pure ASCII) and at the same time target DTCollation
      is ASCII-compatible. For example, no needs to rewrite:
        SELECT * FROM t1 WHERE datetime_field = '2010-01-01';
      to
        SELECT * FROM t1 WHERE CONVERT(datetime_field USING cs) = '2010-01-01';

      TODO: avoid conversion of any values with
      repertoire ASCII and 7bit-ASCII-compatible,
      not only numeric/datetime origin.
    */
    if (collation.derivation == DERIVATION_NUMERIC &&
        collation.repertoire == MY_REPERTOIRE_ASCII &&
        !(collation.collation->state & MY_CS_NONASCII) &&
        !(tocs->state & MY_CS_NONASCII))
      return false;
    return true;
  }


  longlong val_temporal_packed(enum_field_types f_type)
  {
    return f_type == MYSQL_TYPE_TIME ? val_time_packed() :
                                       val_datetime_packed();
  }


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


  Item *next()
  {
    if (current >= base_item->cols())
      return NULL;
    return base_item->element_index(current++);
  }


String_copier_for_item(THD *thd): m_thd(thd) { }


  Item_default_value(THD *thd, Name_resolution_context *context_arg, Field *a)
    :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
                (const char *)NULL),
    arg(NULL),cached_field(NULL) {}


  bool check_vcol_func_processor(void *arg)
  {
    context= 0;
    if (field && (field->unireg_check == Field::NEXT_NUMBER))
    {
      // Auto increment fields are unsupported
      return mark_unsupported_function(field_name, arg, VCOL_FIELD_REF | VCOL_AUTO_INC);
    }
    return mark_unsupported_function(field_name, arg, VCOL_FIELD_REF);
  }


  Item_cache_str_for_nullif(THD *thd, const Item *item)
   :Item_cache_str(thd, item)
  { }


virtual ~Field_enumerator() {};             /* purecov: inspected */


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


  enum_field_types real_field_type() const
  { return Type_handler_hybrid_real_field_type::real_field_type(); }


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


  Item_direct_ref(THD *thd, Name_resolution_context *context_arg, Item **item,
                  const char *table_name_arg,
                  const char *field_name_arg,
                  bool alias_name_used_arg= FALSE):
    Item_ref(thd, context_arg, item, table_name_arg,
             field_name_arg, alias_name_used_arg)
  {}


Item_cache_decimal(THD *thd): Item_cache(thd, MYSQL_TYPE_NEWDECIMAL) {}


void make_field(THD *thd, Send_field *field) { item->make_field(thd, field); }


  bool excl_dep_on_grouping_fields(st_select_lex *sel)
  {
    for (uint i= 0; i < arg_count; i++)
    {
      if (args[i]->const_item())
        continue;
      if (!args[i]->excl_dep_on_grouping_fields(sel))
        return false;
    }
    return true;
  }


Cached_item_int(Item *item_par) :Cached_item_item(item_par),value(0) {}


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


  enum_field_types field_type() const
  {
    return result_field->type();
  }


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


  bool walk(Item_processor processor, bool walk_subquery, void *arg)
  {
    if (walk_args(processor, walk_subquery, arg))
      return true;
    return (this->*processor)(arg);
  }


  bool setup(THD *thd, Item *item)
  {
    if (Item_cache_int::setup(thd, item))
      return true;
    set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
    return false;
  }


  Item_empty_string(THD *thd, const char *header,uint length,
                    CHARSET_INFO *cs= NULL):
    Item_partition_func_safe_string(thd, "", 0,
                                    cs ? cs : &my_charset_utf8_general_ci)
    { name=(char*) header; max_length= length * collation.collation->mbmaxlen; }


  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 check_vcol_func_processor(void *arg)
  {
    return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE);
  }


bool is_expensive() { return orig_item->is_expensive(); }


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


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


  Sql_mode_dependency value_depends_on_sql_mode() const
  {
    return Item_args::value_depends_on_sql_mode_bit_or().soft_to_hard();
  }


  Item_datetime_literal(THD *thd, MYSQL_TIME *ltime, uint dec_arg):
    Item_temporal_literal(thd, ltime, dec_arg)
  {
    max_length= MAX_DATETIME_WIDTH + (decimals ? decimals + 1 : 0);
    fixed= 1;
    // See the comment on maybe_null in Item_date_literal
    maybe_null= !ltime->month || !ltime->day;
  }


inline bool Virtual_column_info::is_equal(const Virtual_column_info* vcol) const
{
  return field_type == vcol->get_real_type()
      && stored_in_db == vcol->is_stored()
      && expr->eq(vcol->expr, true);
}


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


Item_null_result(THD *thd): Item_null(thd), result_field(0) {}


    Metadata(const String *str)
    {
      my_string_metadata_get(this, str->charset(), str->ptr(), str->length());
    }


  const Type_handler *type_handler() const
  {
    return result_field->type_handler();
  }


  bool load_data_add_outvar(THD *thd, Load_data_param *param) const
  {
    return param->add_outvar_field(thd, field);
  }


  void used_tables_and_const_cache_update_and_join(uint argc, Item **argv)
  {
    for (uint i=0 ; i < argc ; i++)
      used_tables_and_const_cache_update_and_join(argv[i]);
  }


  Item_insert_value(THD *thd, Name_resolution_context *context_arg, Item *a)
    :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
               (const char *)NULL),
     arg(a) {}


  Copy_query_with_rewrite(THD *t, const char *s, size_t l, String *d)
    :thd(t), src(s), src_len(l), from(0), dst(d) { }


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


  enum_field_types string_field_type() const
  {
    return Type_handler::string_type_handler(max_length)->field_type();
  }


enum Type type() const { return INSERT_VALUE_ITEM; }


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


  bool eq_def(const Field *field)
  {
    return cached_field ? cached_field->eq_def (field) : FALSE;
  }


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


  Item_int_with_ref(THD *thd, longlong i, Item *ref_arg, bool unsigned_arg):
    Item_int(thd, i), ref(ref_arg)
  {
    unsigned_flag= unsigned_arg;
  }


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


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


  my_decimal *val_decimal(my_decimal *decimal_value)
  { return  val_decimal_from_date(decimal_value); }


virtual Item_result cast_to_int_type() const { return cmp_type(); }


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


  longlong val_int()
  {
    DBUG_ASSERT(fixed == 1);
    return longlong_from_string_with_check(&str_value);
  }


enum_field_types field_type() const { return MYSQL_TYPE_DATE; }


inline void Virtual_column_info::print(String* str)
{
  expr->print_for_table_def(str);
}


  bool int_eq(longlong value, const Item *item) const
  {
    DBUG_ASSERT(is_basic_value(INT_ITEM));
    return is_basic_value(item, INT_ITEM) &&
           value == ((Item_basic_value*)item)->val_int() &&
           (value >= 0 || item->unsigned_flag == unsigned_flag);
  }


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


    Metadata(const String *str, uint repertoire_arg)
    {
      MY_STRING_METADATA::repertoire= repertoire_arg;
      MY_STRING_METADATA::char_length= str->numchars();
    }


inline void remove_arguments() { arg_count=0; }


  uint decimal_precision() const
  { return (uint) (max_length - MY_TEST(value < 0)); }


  Item_cache_int(THD *thd): Item_cache(thd, MYSQL_TYPE_LONGLONG),
    value(0) {}


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


  double val_real()
  {
    DBUG_ASSERT(fixed == 1);
    return double_from_string_with_check(&str_value);
  }


  longlong val_time_packed()
  {
    if (check_null_ref())
      return 0;
    else
      return Item_direct_ref::val_time_packed();
  }


  Item_time_literal(THD *thd, MYSQL_TIME *ltime, uint dec_arg):
    Item_temporal_literal(thd, ltime, dec_arg)
  {
    max_length= MIN_TIME_WIDTH + (decimals ? decimals + 1 : 0);
    fixed= 1;
  }


enum Type real_type() const { return orig_item->type(); }


  virtual void set_join_tab_idx(uint join_tab_idx_arg)
  {
    if (join_tab_idx_arg < join_tab_idx)
      join_tab_idx= join_tab_idx_arg;
  }


  Item_func_or_sum(THD *thd, Item *a, Item *b, Item *c, Item *d, Item *e):
    Item_result_field(thd), Item_args(thd, a, b, c, d, e) { }


  bool check_null_ref()
  {
    DBUG_ASSERT(null_ref_table);
    if (null_ref_table != NO_NULL_TABLE && null_ref_table->null_row)
    {
      null_value= 1;
      return TRUE;
    }
    return FALSE;
  }


  Load_data_outvar *get_load_data_outvar()
  {
    return (*ref)->get_load_data_outvar();
  }


  virtual Item *update_value_transformer(THD *thd, uchar *select_arg)
  { return this; }


  bool check_vcol_func_processor(void *arg)
  { // VCOL_TIME_FUNC because the value is not constant, but does not
    // require fix_fields() to be re-run for every statement.
    return mark_unsupported_function(func_name, arg, VCOL_TIME_FUNC);
  }


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


virtual ~Rewritable_query_parameter() { }


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


  void used_tables_and_const_cache_init()
  {
    used_tables_cache= 0;
    const_item_cache= true;
  }


  bool append(Rewritable_query_parameter *p)
  {
    if (copy_up_to(p->pos_in_query) || p->append_for_log(thd, dst))
      return true;
    from= p->pos_in_query + p->len_in_query;
    return false;
  }


  virtual CHARSET_INFO *charset_for_protocol(void) const
  {
    return cmp_type() == STRING_RESULT ? collation.collation :
                                         &my_charset_bin;
  };


  bool check_cols(uint c)
  {
    return (result_type() == ROW_RESULT ?
            orig_item->check_cols(c) :
            Item::check_cols(c));
  }


virtual table_map all_used_tables() const { return used_tables(); }


  Item *get_tmp_table_item(THD *thd)
  {
    if (const_item())
      return copy_or_same(thd);
    Item *item= Item_ref::get_tmp_table_item(thd);
    item->name= name;
    return item;
  }


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


static inline const char *dbug_print_item(Item *item) { return NULL; }


  Item_field *field_for_view_update()
  { return orig_item->field_for_view_update(); }


  COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
                          bool link_item_fields,
                          COND_EQUAL **cond_equal_ref)
  {
    /*
      normilize_cond() replaced all conditions of type
         WHERE/HAVING field
      to:
        WHERE/HAVING field<>0
      By the time of a build_equal_items() call, all such conditions should
      already be replaced. No Item_field are possible.
      Note, some Item_field derivants are still possible.
      Item_insert_value:
        SELECT * FROM t1 WHERE VALUES(a);
      Item_default_value:
        SELECT * FROM t1 WHERE DEFAULT(a);
    */
    DBUG_ASSERT(type() != FIELD_ITEM);
    return Item_ident::build_equal_items(thd, inherited, link_item_fields,
                                         cond_equal_ref);
  }


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


  bool excl_dep_on_table(table_map tab_map)
  {
    for (uint i= 0; i < arg_count; i++)
    {
      if (args[i]->const_item())
        continue;
      if (!args[i]->excl_dep_on_table(tab_map))
        return false;
    }
    return true;
  }


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


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


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


virtual Item_splocal *get_item_splocal() { return 0; }


  enum Type type() const
  {
    return item_type;
  }


virtual void save_val(Field *to) { save_org_in_field(to, NULL); }


enum_field_types field_type() const { return MYSQL_TYPE_TIME; }


  int get_extraction_flag()
  { return  marker & EXTRACTION_MASK; }


inline Item* get_item_copy (THD *thd, MEM_ROOT *mem_root, T* item)
{
  Item *copy= new (mem_root) T(*item);
  copy->register_in(thd);
  return copy;
}


void set_result_field(Field *field_arg) {}


  Item_return_int(THD *thd, const char *name_arg, uint length,
		  enum_field_types field_type_arg, longlong value_arg= 0):
    Item_int(thd, name_arg, value_arg, length), int_field_type(field_type_arg)
  {
    unsigned_flag=1;
  }


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


  enum Item_result result_type () const
  { return Type_handler_hybrid_field_type::result_type(); }


  Item_direct_ref_to_ident(THD *thd, Item_ident *item):
    Item_direct_ref(thd, item->context, (Item**)&item, item->table_name,
                    item->field_name, FALSE)
  {
    ident= item;
    ref= (Item**)&ident;
  }


  CHARSET_INFO *charset_for_protocol(void) const
  {
    return (*ref)->charset_for_protocol();
  }


  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_cache(THD *thd):
    Item_basic_constant(thd),
    Type_handler_hybrid_field_type(MYSQL_TYPE_STRING),
    example(0), cached_field(0),
    value_cached(0)
  {
    fixed= 1;
    maybe_null= 1;
    null_value= 1;
    null_value_inside= true;
  }


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


  Item_string(THD *thd, CHARSET_INFO *csi, const char *str_arg, uint length_arg):
    Item_basic_constant(thd)
  {
    collation.set(csi, DERIVATION_COERCIBLE);
    set_name(thd, NULL, 0, system_charset_info);
    decimals= NOT_FIXED_DEC;
    fixed= 1;
    str_value.copy(str_arg, length_arg, csi);
    max_length= str_value.numchars() * csi->mbmaxlen;
  }


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


virtual inline void quick_fix_field() { fixed= 1; }


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


Item_hex_hybrid(THD *thd): Item_hex_constant(thd) {}


  Field *make_num_distinct_aggregator_field(MEM_ROOT *mem_root,
                                            const Item *item) const
  {
    return type_handler()->make_num_distinct_aggregator_field(mem_root, this);
  }


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


  Item_blob(THD *thd, const char *name_arg, uint length):
    Item_partition_func_safe_string(thd, name_arg, (uint) strlen(name_arg), &my_charset_bin)
  { max_length= length; }


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


virtual Item *copy_andor_structure(THD *thd) { return this; }


virtual bool allocate(THD *thd, uint i) { return 0; }


  virtual Field *create_tmp_field(bool group, TABLE *table)
  {
    /*
      Values with MY_INT32_NUM_DECIMAL_DIGITS digits may or may not fit into
      Field_long : make them Field_longlong.
    */
    return create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS - 2);
  }


  Field *make_conversion_table_field(TABLE *table,
                                     uint metadata, const Field *target) const
  {
    DBUG_ASSERT(0); // Should not be called in Item context
    return NULL;
  }


  Item_temptable_field(THD *thd, Name_resolution_context *context_arg, Field *field)
   : Item_field(thd, context_arg, field) {}


  virtual bool is_cs_specified() const
  {
    return true;
  }


  longlong val_datetime_packed()
  {
    if (check_null_ref())
      return 0;
    else
      return Item_direct_ref::val_datetime_packed();
  }


  longlong val_int()
  { return val_int_from_date(); }


  uint load_data_fixed_length() const
  {
    return field->field_length;
  }


  bool eval_const_cond()
  {
    DBUG_ASSERT(const_item());
    DBUG_ASSERT(!is_expensive());
    return val_bool();
  }


  enum_field_types field_type() const
  { return Type_handler_hybrid_field_type::field_type(); }


virtual bool cleanup_excluding_fields_processor(void *arg) { return cleanup_processor(arg); }


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


  my_decimal *val_decimal(my_decimal *tmp)
  {
    if (check_null_ref())
      return NULL;
    else
      return Item_direct_ref::val_decimal(tmp);
  }


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


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 bool is_cs_specified() const
  {
    return false;
  }


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


  void update_used_tables()
  {
    update_table_bitmaps();
  }


  Field *create_field_for_schema(THD *thd, TABLE *table)
  { return tmp_table_field_from_field_type(table, false, true); }


  void share_name_with(Item *item)
  {
    name= item->name;
    name_length= item->name_length;
    is_autogenerated_name= item->is_autogenerated_name;
  }


  virtual Item* propagate_equal_fields(THD*, const Context &, COND_EQUAL *)
  {
    return this;
  };


virtual bool dynamic_result() { return 0; }


  table_map view_used_tables(TABLE_LIST *view)
  {
    view->view_used_tables= 0;
    walk(&Item::view_used_tables_processor, 0, view);
    return view->view_used_tables;
  }


  longlong val_int()
  {
    if (check_null_ref())
      return 0;
    else
      return Item_direct_ref::val_int();
  }


  virtual bool change_context_processor(void *cntx)
    { context= (Name_resolution_context *)cntx; return FALSE; }


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


virtual void mark_as_condition_AND_part(TABLE_LIST *embedding) {};


  longlong val_int_from_item(Item *item)
  {
    DBUG_ASSERT(fixed == 1);
    longlong value= item->val_int();
    null_value= item->null_value;
    return value;
  }


  Item_string_sys(THD *thd, const char *str, uint length):
    Item_string(thd, str, length, system_charset_info)
  { }


  void save_org_in_field(Field *field,
                         fast_field_copier data __attribute__ ((__unused__)))
  {
    save_val(field);
  }


virtual bool excl_dep_on_table(table_map tab_map) { return false; }


  bool fix_fields(THD *thd, Item **it)
  {
    if ((!(*ref)->fixed && (*ref)->fix_fields(thd, ref)) ||
        (*ref)->check_cols(1))
      return TRUE;
    return Item_ref::fix_fields(thd, it);
  }


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


  Item_result cast_to_int_type() const
  {
    return field->cmp_type();
  }


  void cleanup()
  {
    null_ref_table= NULL;
    item_equal= NULL;
    Item_direct_ref::cleanup();
  }


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


  my_decimal *val_decimal(my_decimal *decimal_value)
  {
    return val_decimal_from_string(decimal_value);
  }


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


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


  bool check_table_name_processor(void *arg)
  {
    Check_table_name_prm &p= *(Check_table_name_prm *) arg;
    if (p.table_name.length && table_name)
    {
      DBUG_ASSERT(p.db.length);
      if ((db_name &&
          my_strcasecmp(table_alias_charset, p.db.str, db_name)) ||
          my_strcasecmp(table_alias_charset, p.table_name.str, table_name))
      {
        print(&p.field, (enum_query_type) (QT_ITEM_ORIGINAL_FUNC_NULLIF |
                                          QT_NO_DATA_EXPANSION |
                                          QT_TO_SYSTEM_CHARSET));
        return true;
      }
    }
    return false;
  }


  Item_cache_str(THD *thd, const Item *item):
    Item_cache(thd, item->field_type()), value(0),
    is_varbinary(item->type() == FIELD_ITEM &&
                 Item_cache_str::field_type() == MYSQL_TYPE_VARCHAR &&
                 !((const Item_field *) item)->field->has_charset())
  {
    collation.set(const_cast<DTCollation&>(item->collation));
  }


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


  bool get_time(MYSQL_TIME *ltime)
  { return get_date(ltime, TIME_TIME_ONLY | TIME_INVALID_DATES); }


  virtual bool check_equality(THD *thd, COND_EQUAL *cond, List<Item> *eq_list)
  {
    return false;
  }


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


  enum precedence higher_precedence() const
  { return (enum precedence)(precedence() + 1); }


    bool needs_conversion() const
    {
      return final_character_set_of_str_value !=
             character_set_of_placeholder;
    }


  void update_used_tables()
  {
    orig_item->update_used_tables();
  }


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


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


virtual bool is_json_type() { return false; }


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


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


Item_result cmp_type() const { return TIME_RESULT; }


  bool const_item() const
  {
    return (*ref)->const_item() && (null_ref_table == NO_NULL_TABLE);
  }


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


  Item_null(THD *thd, char *name_par=0, CHARSET_INFO *cs= &my_charset_bin):
    Item_basic_constant(thd)
  {
    maybe_null= null_value= TRUE;
    max_length= 0;
    name= name_par ? name_par : (char*) "NULL";
    fixed= 1;
    collation.set(cs, DERIVATION_IGNORABLE, MY_REPERTOIRE_ASCII);
  }


bool const_item() const { return orig_item->const_item(); }


  Item_func_or_sum(THD *thd, Item *a, Item *b, Item *c, Item *d):
    Item_result_field(thd), Item_args(thd, a, b, c, d) { }


  virtual void fix_after_pullout(st_select_lex *new_parent, Item **ref,
                                 bool merge)
    {};


bool eq(const Item *item, bool binary_cmp) const { return null_eq(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;
  }


  Item_temptable_field(THD *thd, Field *field)
   : Item_field(thd, field) {}


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


TABLE *get_null_ref_table() const { return null_ref_table; }


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


  enum_field_types field_type() const
  { return Type_handler_hybrid_real_field_type::field_type(); }


  void fix_char_length(size_t max_char_length_arg)
  {
    max_length= char_to_byte_length_safe(max_char_length_arg,
                                         collation.collation->mbmaxlen);
  }


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


  Item_temporal_literal(THD *thd, MYSQL_TIME *ltime, uint dec_arg):
    Item_basic_constant(thd)
  {
    collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII);
    decimals= dec_arg;
    cached_time= *ltime;
  }


  Used_tables_and_const_cache(const Used_tables_and_const_cache *other)
   :used_tables_cache(other->used_tables_cache),
    const_item_cache(other->const_item_cache)
  { }


virtual bool excl_dep_on_grouping_fields(st_select_lex *sel) { return false; }


  bool excl_dep_on_grouping_fields(st_select_lex *sel)
  { return (*ref)->excl_dep_on_grouping_fields(sel); }


  bool get_date_from_item(Item *item, MYSQL_TIME *ltime, ulonglong fuzzydate)
  {
    bool rc= item->get_date(ltime, fuzzydate);
    null_value= MY_TEST(rc || item->null_value);
    return rc;
  }


Item_splocal *get_item_splocal() { return this; }


  Item_int(THD *thd, const char *str_arg,longlong i,uint length):
    Item_num(thd), value(i)
    { max_length=length; name=(char*) str_arg; fixed= 1; }


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


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


Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }


  enum precedence precedence() const
  {
    return ref ? (*ref)->precedence() : DEFAULT_PRECEDENCE;
  }


  bool copy_up_to(size_t bytes)
  {
    DBUG_ASSERT(bytes >= from);
    return dst->append(src + from, uint32(bytes - from));
  }


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


  virtual void print(String *str, enum_query_type query_type)
  { ident->print(str, query_type); }


  String *val_str(String *str)
  { return val_string_from_date(str); }


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


  void print_for_table_def(String *str)
  {
    print_parenthesised(str,
                     (enum_query_type)(QT_ITEM_ORIGINAL_FUNC_NULLIF |
                                       QT_ITEM_IDENT_SKIP_DB_NAMES |
                                       QT_ITEM_IDENT_SKIP_TABLE_NAMES |
                                       QT_NO_DATA_EXPANSION |
                                       QT_TO_SYSTEM_CHARSET),
                     LOWEST_PRECEDENCE);
  }


  Item_args(Item *a)
    :args(tmp_arg), arg_count(1)
  {
    args[0]= a;
  }


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


  virtual Item *expr_cache_insert_transformer(THD *thd, uchar *unused)
  { return this; }


  Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
  {
    /**
      Item_cache_str::safe_charset_converter() returns a new Item_cache
      with Item_func_conv_charset installed on "example". The original
      Item_cache is not referenced (neither directly nor recursively)
      from the result of Item_cache_str::safe_charset_converter().

      For NULLIF() purposes we need a different behavior:
      we need a new instance of Item_func_conv_charset,
      with the original Item_cache referenced in args[0]. See MDEV-9181.
    */
    return Item::safe_charset_converter(thd, tocs);
  }


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


virtual bool cleanup_excluding_const_fields_processor(void *arg) { return cleanup_processor(arg); }


  bool walk_args(Item_processor processor, bool walk_subquery, void *arg)
  {
    for (uint i= 0; i < arg_count; i++)
    {
      if (args[i]->walk(processor, walk_subquery, arg))
        return true;
    }
    return false;
  }


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


enum Type type() const { return DATE_ITEM; }


  void make_field(THD *thd, Send_field *)
  {
    illegal_method_call((const char*)"make_field");
  };


table_map used_tables() const { return orig_item->used_tables(); }


  virtual void save_org_in_field(Field *field,
                                 fast_field_copier data
                                 __attribute__ ((__unused__)))
  { (void) save_in_field(field, 1); }


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


bool const_item() const { return const_item_cache; }


  bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
  {
    if (check_null_ref())
    {
      bzero((char*) ltime,sizeof(*ltime));
      return 1;
    }
    return Item_direct_ref::get_date(ltime, fuzzydate);
  }


inline uint argument_count() const { return arg_count; }


  Item_func_or_sum(THD *thd, Item *a, Item *b):
    Item_result_field(thd), Item_args(a, b) { }


Item_result_field(THD *thd): Item(thd), result_field(0) {}


  bool agg_arg_charsets(DTCollation &c, Item **items, uint nitems,
                        uint flags, int item_sep)
  {
    if (agg_item_collations(c, func_name(), items, nitems, flags, item_sep))
      return true;

    return agg_item_set_converter(c, func_name(), items, nitems,
                                  flags, item_sep);
  }


  bool val_bool()
  {
    if (check_null_ref())
      return 0;
    else
      return Item_direct_ref::val_bool();
  }


  Item_args(Item *a, Item *b)
    :args(tmp_arg), arg_count(2)
  {
    args[0]= a; args[1]= b;
  }


virtual Item *clone_item(THD *thd) { return 0; }


Item_copy_string(THD *thd, Item *item_arg): Item_copy(thd, item_arg) {}


  Item_string(THD *thd, const String *str, CHARSET_INFO *tocs, uint *conv_errors,
              Derivation dv, uint repertoire): Item_basic_constant(thd)
  {
    if (str_value.copy(str, tocs, conv_errors))
      str_value.set("", 0, tocs); // EOM ?
    str_value.mark_as_const();
    fix_and_set_name_from_value(thd, dv, Metadata(&str_value, repertoire));
  }


  void fix_and_set_name_from_value(THD *thd, Derivation dv,
                                   const Metadata metadata)
  {
    fix_from_value(dv, metadata);
    set_name(thd, str_value.ptr(), str_value.length(), str_value.charset());
  }


Item_hex_string(THD *thd): Item_hex_constant(thd) {}


  double val_real()
  { return val_real_from_date(); }


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


  Item_func_or_sum(THD *thd, Item *a, Item *b, Item *c):
    Item_result_field(thd), Item_args(thd, a, b, c) { }


  bool get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
  {
    *ltime= cached_time;
    return (null_value= false);
  }


bool check_partition_func_processor(void *int_arg) {return TRUE;}


virtual String *val_json(String *str) { return val_str(str); }


  Item_static_string_func(THD *thd, const char *name_par, const char *str,
                          uint length, CHARSET_INFO *cs,
                          Derivation dv= DERIVATION_COERCIBLE):
    Item_string(thd, NullS, str, length, cs, dv), func_name(name_par)
  {}


  Item_default_value(THD *thd, Name_resolution_context *context_arg)
    :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
               (const char *)NULL),
    arg(NULL), cached_field(NULL) {}


  void used_tables_and_const_cache_update_and_join(List<Item> &list)
  {
    List_iterator_fast<Item> li(list);
    Item *item;
    while ((item=li++))
      used_tables_and_const_cache_update_and_join(item);
  }


  void restore_to_before_no_rows_in_result()
  {
    (*ref)->restore_to_before_no_rows_in_result();
  }


  bool save_in_param(THD *thd, Item_param *param)
  {
    param->set_ignore();
    return false;
  }


  bool depends_only_on(table_map view_map)
  { return marker & FULL_EXTRACTION_FL; }


  my_decimal *val_decimal_from_item(Item *item, my_decimal *decimal_value)
  {
    DBUG_ASSERT(fixed == 1);
    my_decimal *value= item->val_decimal(decimal_value);
    if ((null_value= item->null_value))
      value= NULL;
    return value;
  }


  Rewritable_query_parameter *get_rewritable_query_parameter()
  { return this; }


  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 fix_fields(THD *thd, Item **it)
  {
    DBUG_ASSERT(ident->type() == FIELD_ITEM || ident->type() == REF_ITEM);
    if ((!ident->fixed && ident->fix_fields(thd, ref)) ||
        ident->check_cols(1))
      return TRUE;
    set_properties();
    return FALSE;
  }


Item_equal *get_item_equal() { return item_equal; }


  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 count_sargable_conds(void *arg) { return 0; }


  bool cleanup_is_expensive_cache_processor(void *arg)
  {
    is_expensive_cache= (int8)(-1);
    return 0;
  }


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


  Item *const_charset_converter(THD *thd, CHARSET_INFO *tocs, bool lossless)
  { return const_charset_converter(thd, tocs, lossless, NULL); }


  void set(const Field *field)
  {
    decimals= field->decimals();
    max_length= field->field_length;
    collation.set(field->charset());
    unsigned_flag= MY_TEST(field->flags & UNSIGNED_FLAG);
  }


  Load_data_outvar *get_load_data_outvar()
  {
    return this;
  }


virtual Item_equal *find_item_equal(COND_EQUAL *cond_equal) { return NULL; }


  static Item_cache* get_cache(THD *thd, const Item *item)
  {
    return get_cache(thd, item, item->cmp_type());
  }


enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }


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


  virtual Sql_mode_dependency value_depends_on_sql_mode() const
  {
    return Sql_mode_dependency();
  }


Item_func_or_sum(THD *thd, Item *a): Item_result_field(thd), Item_args(a) { }


  Item_func_or_sum(THD *thd, Item_func_or_sum *item):
    Item_result_field(thd, item), Item_args(thd, item),
    Used_tables_and_const_cache(item) { }


  void fix_after_pullout(st_select_lex *new_parent, Item **refptr, bool merge)
  {
    orig_item->fix_after_pullout(new_parent, &orig_item, merge);
  }


  Settable_routine_parameter *get_settable_routine_parameter()
  { return m_is_settable_routine_parameter ? this : NULL; }


  bool basic_const_item() const
  { return example && example->basic_const_item(); }


  bool check_vcol_func_processor(void *arg)
  {
    if (example)
    {
      Item::vcol_func_processor_result *res= (Item::vcol_func_processor_result*)arg;
      example->check_vcol_func_processor(arg);
      /*
        Item_cache of a non-deterministic function requires re-fixing
        even if the function itself doesn't (e.g. CURRENT_TIMESTAMP)
      */
      if (res->errors & VCOL_NOT_STRICTLY_DETERMINISTIC)
        res->errors|= VCOL_SESSION_FUNC;
      return false;
    }
    return mark_unsupported_function("cache", arg, VCOL_IMPOSSIBLE);
  }


  bool cleanup_excluding_fields_processor(void *arg)
  {
    Item *item= real_item();
    if (item && item->type() == FIELD_ITEM &&
        ((Item_field *)item)->field)
      return 0;
    return cleanup_processor(arg);
  }


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


  enum Type real_type() const           { return ref ? (*ref)->type() :
                                          REF_ITEM; }


  bool load_data_set_value(THD *thd, const char *pos, uint length,
                           const Load_data_param *param)
  {
    field->load_data_set_value(pos, length, param->charset());
    return false;
  }


  bool cleanup_excluding_fields_processor(void *arg)
  { return field ? 0 : cleanup_processor(arg); }


  void fix_charset_and_length_from_str_value(Derivation dv)
  {
    fix_charset_and_length_from_str_value(dv, Metadata(&str_value));
  }


  CHARSET_INFO *charset_for_protocol(void) const
  {
    return collation.collation;
  }


  Item_bool(THD *thd, const char *str_arg, longlong i):
    Item_int(thd, str_arg, i, 1) {}


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


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


virtual Item *convert_to_basic_const_item(THD *thd) { return 0; };


  bool eq(const Item *item, bool binary_cmp) const
  {
    Item *it= ((Item *) item)->real_item();
    return orig_item->eq(it, binary_cmp);
  }


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


  bool check_vcol_func_processor(void *arg)
  {
    return mark_unsupported_function("values()", arg, VCOL_IMPOSSIBLE);
  }


  bool check_vcol_func_processor(void *arg)
  {
    return mark_unsupported_function("ref", arg, VCOL_IMPOSSIBLE);
  }


  void save_in_result_field(bool no_conversions)
  {
    save_val(result_field);
  }


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


  virtual void make_field(THD *thd, Send_field *field)
  { orig_item->make_field(thd, field); }


  Item** addr(uint i)
  { return result_type() == ROW_RESULT ? orig_item->addr(i) : 0; }


  Item_field *field_for_view_update()
    { return (*ref)->field_for_view_update(); }


  Type_std_attributes(const Type_std_attributes *other)
   :collation(other->collation),
    decimals(other->decimals),
    max_length(other->max_length),
    unsigned_flag(other->unsigned_flag)
  { }


  bool value_depends_on_sql_mode_const_item()
  {
    /*
      Currently we use value_depends_on_sql_mode() only for virtual
      column expressions. They should not contain any expensive items.
      If we ever get a crash on the assert below, it means
      check_vcol_func_processor() is badly implemented for this item.
    */
    DBUG_ASSERT(!is_expensive());
    /*
      It should return const_item() actually.
      But for some reasons Item_field::const_item() returns true
      at value_depends_on_sql_mode() call time.
      This should be checked and fixed.
    */
    return basic_const_item();
  }


  Item_partition_func_safe_string(THD *thd, const char *name_arg, uint length,
                                  CHARSET_INFO *cs= NULL):
    Item_string(thd, name_arg, length, cs)
  {}


Item *get_example() const { return example; }


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


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


virtual bool check_table_name_processor(void *arg) { return false; }


  String *check_well_formed_result(bool send_error)
  { return Item::check_well_formed_result(&str_value, send_error); }


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


  Item_string(THD *thd, const char *name_par, const char *str, uint length,
              CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE):
    Item_basic_constant(thd)
  {
    str_value.set_or_copy_aligned(str, length, cs);
    fix_from_value(dv, Metadata(&str_value));
    set_name(thd, name_par, 0, system_charset_info);
  }


  bool null_eq(const Item *item) const
  {
    DBUG_ASSERT(is_basic_value(NULL_ITEM));
    return item->type() == NULL_ITEM;
  }


  fast_field_copier setup_fast_field_copier(Field *field)
  { return (*ref)->setup_fast_field_copier(field); }


bool update_vcol_processor(void *arg) { return 0; }


  bool walk(Item_processor processor, bool walk_subquery, void *arg)
  {
    if (example && example->walk(processor, walk_subquery, arg))
      return TRUE;
    return (this->*processor)(arg);
  }


  Item_iterator_list(List_iterator<Item> &arg_list):
    list(arg_list) {}


  void fix_charset_and_length_from_str_value(Derivation dv, Metadata metadata)
  {
    /*
      We have to have a different max_length than 'length' here to
      ensure that we get the right length if we do use the item
      to create a new table. In this case max_length must be the maximum
      number of chars for a string of this type because we in Create_field::
      divide the max_length with mbmaxlen).
    */
    collation.set(str_value.charset(), dv, metadata.repertoire());
    fix_char_length(metadata.char_length());
    decimals= NOT_FIXED_DEC;
  }


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


  bool is_null()
  { return is_null_from_temporal(); }


  Item *derived_field_transformer_for_having(THD *thd, uchar *arg)
  { return convert_to_basic_const_item(thd); }


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


  bool has_int_value() const
  {
    return state == INT_VALUE;
  }


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


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


virtual const char *full_name() const { return orig_item->full_name(); }


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


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


  void save_val(Field *to)
  {
    if (check_null_ref())
      to->set_null();
    else
      Item_direct_ref::save_val(to);
  }


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


  enum Item_result result_type () const
  {
    /*
      In 10.1 Item_type_holder::result_type() returned
      Field::result_merge_type(field_type()), which returned STRING_RESULT
      for the BIT data type. In 10.2 it returns INT_RESULT, similar
      to what Field_bit::result_type() does. This should not be
      important because Item_type_holder is a limited purpose Item
      and its result_type() should not be called from outside of
      Item_type_holder. It's called only internally from decimal_int_part()
      from join_types(), to calculate "decimals" of the result data type.
      As soon as we get BIT as one of the joined types, the result field
      type cannot be numeric: it's either BIT, or VARBINARY.
    */
    return Type_handler_hybrid_real_field_type::result_type();
  }


  virtual Rewritable_query_parameter *get_rewritable_query_parameter()
  { return 0; }


  Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a)
    :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
                (const char *)NULL),
    arg(a), cached_field(NULL) {}


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


  Item_trigger_field(THD *thd, Name_resolution_context *context_arg,
                     row_version_type row_ver_arg,
                     const char *field_name_arg,
                     ulong priv, const bool ro)
    :Item_field(thd, context_arg,
               (const char *)NULL, (const char *)NULL, field_name_arg),
     row_version(row_ver_arg), field_idx((uint)-1), original_privilege(priv),
     want_privilege(priv), table_grants(NULL), read_only (ro)
  {}


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


uint repertoire() const { return MY_STRING_METADATA::repertoire; }


  Item_ref(THD *thd, Item_ref *item)
    :Item_ident(thd, item), set_properties_only(0), ref(item->ref) {}


Item_temptable_field(THD *thd, Item_field *item) : Item_field(thd, item) {};


  virtual bool is_expensive()
  {
    if (value_cached)
      return false;
    return example->is_expensive();
  }


bool is_result_field() { return false; }


  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 void update_null_value ()
  {
    switch (cmp_type()) {
    case INT_RESULT:
      (void) val_int();
      break;
    case REAL_RESULT:
      (void) val_real();
      break;
    case DECIMAL_RESULT:
      {
        my_decimal tmp;
        (void) val_decimal(&tmp);
      }
      break;
    case TIME_RESULT:
      {
        MYSQL_TIME ltime;
        (void) get_temporal_with_sql_mode(&ltime);
      }
      break;
    case STRING_RESULT:
      {
        StringBuffer<MAX_FIELD_WIDTH> tmp;
        (void) val_str(&tmp);
      }
      break;
    case ROW_RESULT:
      DBUG_ASSERT(0);
      null_value= true;
    }
  }


  String *val_str_from_item(Item *item, String *str)
  {
    DBUG_ASSERT(fixed == 1);
    String *res= item->val_str(str);
    if (res)
      res->set_charset(collation.collation);
    if ((null_value= item->null_value))
      res= NULL;
    return res;
  }


virtual bool expr_cache_is_needed(THD *) { return FALSE; }


  Item_string_ascii(THD *thd, const char *str):
    Item_string(thd, str, (uint)strlen(str), &my_charset_latin1,
                DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII)
  { }


  Item_outer_ref(THD *thd, Name_resolution_context *context_arg,
                 Item_field *outer_field_arg):
    Item_direct_ref(thd, context_arg, 0, outer_field_arg->table_name,
                    outer_field_arg->field_name),
    outer_ref(outer_field_arg), in_sum_func(0),
    found_in_select_list(0), found_in_group_by(0)
  {
    ref= &outer_ref;
    set_properties();
    fixed= 0;                     /* reset flag set in set_properties() */
  }


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


static void operator delete(void *ptr,size_t size) { TRASH_FREE(ptr, size); }


virtual void set_item_equal(Item_equal *item_eq) {};


  bool load_data_set_null(THD *thd, const Load_data_param *param)
  {
    return field->load_data_set_null(thd);
  }


bool const_item() const { return true; }


  Item_ident_for_show(THD *thd, Field *par_field, const char *db_arg,
                      const char *table_name_arg):
    Item(thd), field(par_field), db_name(db_arg), table_name(table_name_arg)
  {}


    Check_table_name_prm(LEX_CSTRING _db, LEX_CSTRING _table_name) :
      db(_db), table_name(_table_name) {}


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


Item *build_clone(THD *thd, MEM_ROOT *mem_root) { return 0; }


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


virtual uint exists2in_reserved_items() { return 0; };


Item_func_or_sum(THD *thd): Item_result_field(thd), Item_args() {}


  Item_cache_int(THD *thd, enum_field_types field_type_arg):
    Item_cache(thd, field_type_arg), value(0) {}


  double val_real()
  {
    if (check_null_ref())
      return 0;
    else
      return Item_direct_ref::val_real();
  }


  bool store(struct st_value *value, ulonglong fuzzydate)
  {
    switch (cmp_type()) {
    case INT_RESULT:
    {
      value->m_type= unsigned_flag ? DYN_COL_UINT : DYN_COL_INT;
      value->value.m_longlong= val_int();
      break;
    }
    case REAL_RESULT:
    {
      value->m_type= DYN_COL_DOUBLE;
      value->value.m_double= val_real();
      break;
    }
    case DECIMAL_RESULT:
    {
      value->m_type= DYN_COL_DECIMAL;
      my_decimal *dec= val_decimal(&value->m_decimal);
      if (dec != &value->m_decimal && !null_value)
        my_decimal2decimal(dec, &value->m_decimal);
      break;
    }
    case STRING_RESULT:
    {
      value->m_type= DYN_COL_STRING;
      String *str= val_str(&value->m_string);
      if (str != &value->m_string && !null_value)
        value->m_string.set(str->ptr(), str->length(), str->charset());
      break;
    }
    case TIME_RESULT:
    {
      value->m_type= DYN_COL_DATETIME;
      get_date(&value->value.m_time, fuzzydate);
      break;
    }
    case ROW_RESULT:
      DBUG_ASSERT(false);
      null_value= true;
      break;
    }
    if (null_value)
    {
      value->m_type= DYN_COL_NULL;
      return true;
    }
    return false;
  }


  virtual bool setup(THD *thd, Item *item)
  {
    example= item;
    Type_std_attributes::set(item);
    if (item->type() == FIELD_ITEM)
      cached_field= ((Item_field *)item)->field;
    return 0;
  };


  Item_string_sys(THD *thd, const char *str):
    Item_string(thd, str, (uint) strlen(str), system_charset_info)
  { }


  longlong val_time_packed_result()
  {
    MYSQL_TIME ltime;
    uint fuzzydate= TIME_TIME_ONLY | TIME_INVALID_DATES | TIME_FUZZY_DATES;
    return get_date_result(&ltime, fuzzydate) ? 0 : pack_time(&ltime);
  }


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


void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; }


  Longlong_hybrid to_longlong_hybrid()
  {
    return Longlong_hybrid(val_int(), unsigned_flag);
  }


virtual void restore_to_before_no_rows_in_result() {}


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


  enum_field_types field_type_for_temporal_comparison(const Item *other) const
  {
    if (cmp_type() == TIME_RESULT)
    {
      if (other->cmp_type() == TIME_RESULT)
        return Field::field_type_merge(field_type(), other->field_type());
      else
        return field_type();
    }
    else
    {
      if (other->cmp_type() == TIME_RESULT)
        return other->field_type();
      DBUG_ASSERT(0); // Two non-temporal data types, we should not get to here
      return MYSQL_TYPE_DATETIME;
    }
  }


  bool vcol_assignment_allowed_value() const
  {
    switch (state) {
    case NULL_VALUE:
    case DEFAULT_VALUE:
    case IGNORE_VALUE:
      return true;
    case NO_VALUE:
    case INT_VALUE:
    case REAL_VALUE:
    case STRING_VALUE:
    case TIME_VALUE:
    case LONG_DATA_VALUE:
    case DECIMAL_VALUE:
      break;
    }
    return false;
  }


  virtual Item* compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
                        Item_transformer transformer, uchar *arg_t)
  {
    if ((this->*analyzer) (arg_p))
      return ((this->*transformer) (thd, arg_t));
    return 0;
  }


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


  Item_hex_constant(THD *thd, const char *str, uint str_length):
    Item_basic_constant(thd)
  {
    hex_string_init(thd, str, str_length);
  }


  longlong val_int()
  {
    // following assert is redundant, because fixed=1 assigned in constructor
    DBUG_ASSERT(fixed == 1);
    return longlong_from_hex_hybrid(str_value.ptr(), str_value.length());
  }


  virtual Load_data_outvar *get_load_data_outvar()
  {
    return 0;
  }


  virtual COND *build_equal_items(THD *thd, COND_EQUAL *inheited,
                                  bool link_item_fields,
                                  COND_EQUAL **cond_equal_ref)
  {
    update_used_tables();
    DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]);
    return this;
  }


  int save_in_field(Field *field, bool no_conversions)
  { return save_date_in_field(field); }


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


  virtual void add_key_fields(JOIN *join, KEY_FIELD **key_fields,
                              uint *and_level,
                              table_map usable_tables,
                              SARGABLE_PARAM **sargables)
  {
    return;
  }


  uint decimal_scale() const
  {
    return decimals < NOT_FIXED_DEC ? decimals :
           is_temporal_type_with_time(field_type()) ?
           TIME_SECOND_PART_DIGITS :
           MY_MIN(max_length, DECIMAL_MAX_SCALE);
  }


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


Field_enumerator() {}                       /* Remove gcc warning */


  inline uint float_length(uint decimals_par) const
  { return decimals < FLOATING_POINT_DECIMALS ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;}


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


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


Item_datetime(THD *thd): Item_int(thd, 0) { unsigned_flag=0; }


  virtual bool get_date_result(MYSQL_TIME *ltime, ulonglong fuzzydate)
  { return get_date(ltime,fuzzydate); }


  bool view_used_tables_processor(void *arg)
  {
    TABLE_LIST *view_arg= (TABLE_LIST *) arg;
    if (view_arg == view)
      view_arg->view_used_tables|= (*ref)->used_tables();
    return 0;
  }


  bool too_big_for_varchar() const
  { return max_char_length() > CONVERT_IF_BIGGER_TO_BLOB; }


open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
                            Open_tables_backup *backup)
{
  Query_tables_list query_tables_list_backup;
  LEX *lex= thd->lex;
  DBUG_ENTER("open_system_tables_for_read");

  /*
    Besides using new Open_tables_state for opening system tables,
    we also have to backup and reset/and then restore part of LEX
    which is accessed by open_tables() in order to determine if
    prelocking is needed and what tables should be added for it.
    close_system_tables() doesn't require such treatment.
  */
  lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
  thd->reset_n_backup_open_tables_state(backup);
  thd->lex->sql_command= SQLCOM_SELECT;

  /*
    Only use MYSQL_LOCK_IGNORE_TIMEOUT for tables opened for read.
    This is to ensure that lock_wait_timeout is honored when trying
    to update stats tables.
  */
  if (open_and_lock_tables(thd, table_list, FALSE,
                           (MYSQL_OPEN_IGNORE_FLUSH |
                            (table_list->lock_type < TL_WRITE_ALLOW_WRITE ?
                             MYSQL_LOCK_IGNORE_TIMEOUT : 0))))
  {
    lex->restore_backup_query_tables_list(&query_tables_list_backup);
    thd->restore_backup_open_tables_state(backup);
    DBUG_RETURN(TRUE);
  }

  for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global)
  {
    DBUG_ASSERT(tables->table->s->table_category == TABLE_CATEGORY_SYSTEM);
    tables->table->use_all_columns();
  }
  lex->restore_backup_query_tables_list(&query_tables_list_backup);

  DBUG_RETURN(FALSE);
}

MDEV-28097 use-after-free when WHERE has subquery with an outer reference in HAVING

when resolving WHERE and ON clauses, do not look in
SELECT list/aliases.


  bool got_fatal_error()
  {
    return unhandled_errors > 0;
  }


bool open_tables(THD *thd, const DDL_options_st &options,
                 TABLE_LIST **start, uint *counter, uint flags,
                 Prelocking_strategy *prelocking_strategy)
{
  /*
    We use pointers to "next_global" member in the last processed
    TABLE_LIST element and to the "next" member in the last processed
    Sroutine_hash_entry element as iterators over, correspondingly,
    the table list and stored routines list which stay valid and allow
    to continue iteration when new elements are added to the tail of
    the lists.
  */
  TABLE_LIST **table_to_open;
  Sroutine_hash_entry **sroutine_to_open;
  TABLE_LIST *tables;
  Open_table_context ot_ctx(thd, flags);
  bool error= FALSE;
  bool some_routine_modifies_data= FALSE;
  bool has_prelocking_list;
  DBUG_ENTER("open_tables");

  /* Data access in XA transaction is only allowed when it is active. */
  for (TABLE_LIST *table= *start; table; table= table->next_global)
    if (!table->schema_table)
    {
      if (thd->transaction.xid_state.check_has_uncommitted_xa())
      {
	thd->transaction.xid_state.er_xaer_rmfail();
        DBUG_RETURN(true);
      }
      else
        break;
    }

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

  has_prelocking_list= thd->lex->requires_prelocking();
  table_to_open= start;
  sroutine_to_open= &thd->lex->sroutines_list.first;
  *counter= 0;
  THD_STAGE_INFO(thd, stage_opening_tables);
  prelocking_strategy->reset(thd);

  /*
    If we are executing LOCK TABLES statement or a DDL statement
    (in non-LOCK TABLES mode) we might have to acquire upgradable
    semi-exclusive metadata locks (SNW or SNRW) on some of the
    tables to be opened.
    When executing CREATE TABLE .. If NOT EXISTS .. SELECT, the
    table may not yet exist, in which case we acquire an exclusive
    lock.
    We acquire all such locks at once here as doing this in one
    by one fashion may lead to deadlocks or starvation. Later when
    we will be opening corresponding table pre-acquired metadata
    lock will be reused (thanks to the fact that in recursive case
    metadata locks are acquired without waiting).
  */
  if (! (flags & (MYSQL_OPEN_HAS_MDL_LOCK |
                  MYSQL_OPEN_FORCE_SHARED_MDL |
                  MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)))
  {
    if (thd->locked_tables_mode)
    {
      /*
        Under LOCK TABLES, we can't acquire new locks, so we instead
        need to check if appropriate locks were pre-acquired.
      */
      if (open_tables_check_upgradable_mdl(thd, *start,
                                           thd->lex->first_not_own_table(),
                                           flags))
      {
        error= TRUE;
        goto error;
      }
    }
    else
    {
      TABLE_LIST *table;
      if (lock_table_names(thd, options, *start,
                           thd->lex->first_not_own_table(),
                           ot_ctx.get_timeout(), flags))
      {
        error= TRUE;
        goto error;
      }
      for (table= *start; table && table != thd->lex->first_not_own_table();
           table= table->next_global)
      {
        if (table->mdl_request.type >= MDL_SHARED_UPGRADABLE)
          table->mdl_request.ticket= NULL;
      }
    }
  }

  /*
    Perform steps of prelocking algorithm until there are unprocessed
    elements in prelocking list/set.
  */
  while (*table_to_open  ||
         (thd->locked_tables_mode <= LTM_LOCK_TABLES && *sroutine_to_open))
  {
    /*
      For every table in the list of tables to open, try to find or open
      a table.
    */
    for (tables= *table_to_open; tables;
         table_to_open= &tables->next_global, tables= tables->next_global)
    {
      error= open_and_process_table(thd, tables, counter, flags,
                                    prelocking_strategy, has_prelocking_list,
                                    &ot_ctx);

      if (unlikely(error))
      {
        if (ot_ctx.can_recover_from_failed_open())
        {
          /*
            We have met exclusive metadata lock or old version of table.
            Now we have to close all tables and release metadata locks.
            We also have to throw away set of prelocked tables (and thus
            close tables from this set that were open by now) since it
            is possible that one of tables which determined its content
            was changed.

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

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

          /*
            Here we rely on the fact that 'tables' still points to the valid
            TABLE_LIST element. Altough currently this assumption is valid
            it may change in future.
          */
          if (ot_ctx.recover_from_failed_open())
            goto error;

          /* Re-open temporary tables after close_tables_for_reopen(). */
          if (thd->open_temporary_tables(*start))
            goto error;

          error= FALSE;
          goto restart;
        }
        goto error;
      }

      DEBUG_SYNC(thd, "open_tables_after_open_and_process_table");
    }

    /*
      If we are not already in prelocked mode and extended table list is
      not yet built for our statement we need to cache routines it uses
      and build the prelocking list for it.
      If we are not in prelocked mode but have built the extended table
      list, we still need to call open_and_process_routine() to take
      MDL locks on the routines.
    */
    if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
    {
      /*
        Process elements of the prelocking set which are present there
        since parsing stage or were added to it by invocations of
        Prelocking_strategy methods in the above loop over tables.

        For example, if element is a routine, cache it and then,
        if prelocking strategy prescribes so, add tables it uses to the
        table list and routines it might invoke to the prelocking set.
      */
      for (Sroutine_hash_entry *rt= *sroutine_to_open; rt;
           sroutine_to_open= &rt->next, rt= rt->next)
      {
        bool need_prelocking= false;
        bool routine_modifies_data;
        TABLE_LIST **save_query_tables_last= thd->lex->query_tables_last;

        error= open_and_process_routine(thd, thd->lex, rt, prelocking_strategy,
                                        has_prelocking_list, &ot_ctx,
                                        &need_prelocking,
                                        &routine_modifies_data);

        // Remember if any of SF modifies data.
        some_routine_modifies_data|= routine_modifies_data;

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

        if (need_prelocking && ! *start)
          *start= thd->lex->query_tables;

        if (unlikely(error))
        {
          if (ot_ctx.can_recover_from_failed_open())
          {
            close_tables_for_reopen(thd, start,
                                    ot_ctx.start_of_statement_svp());
            if (ot_ctx.recover_from_failed_open())
              goto error;

            /* Re-open temporary tables after close_tables_for_reopen(). */
            if (thd->open_temporary_tables(*start))
              goto error;

            error= FALSE;
            goto restart;
          }
          /*
            Serious error during reading stored routines from mysql.proc table.
            Something is wrong with the table or its contents, and an error has
            been emitted; we must abort.
          */
          goto error;
        }
      }
    }
    if ((error= prelocking_strategy->handle_end(thd)))
      goto error;
  }

  /*
    After successful open of all tables, including MERGE parents and
    children, attach the children to their parents. At end of statement,
    the children are detached. Attaching and detaching are always done,
    even under LOCK TABLES.

    We also convert all TL_WRITE_DEFAULT and TL_READ_DEFAULT locks to
    appropriate "real" lock types to be used for locking and to be passed
    to storage engine.

    And start wsrep TOI if needed.
  */
  for (tables= *start; tables; tables= tables->next_global)
  {
    TABLE *tbl= tables->table;

    if (!tbl)
      continue;

    /* Schema tables may not have a TABLE object here. */
    if (tbl->file->ha_table_flags() & HA_CAN_MULTISTEP_MERGE)
    {
      /* MERGE tables need to access parent and child TABLE_LISTs. */
      DBUG_ASSERT(tbl->pos_in_table_list == tables);
      if (tbl->file->extra(HA_EXTRA_ATTACH_CHILDREN))
      {
        error= TRUE;
        goto error;
      }
    }

    /* Set appropriate TABLE::lock_type. */
    if (tbl && tables->lock_type != TL_UNLOCK && !thd->locked_tables_mode)
    {
      if (tables->lock_type == TL_WRITE_DEFAULT)
        tbl->reginfo.lock_type= thd->update_lock_default;
      else if (tables->lock_type == TL_READ_DEFAULT)
          tbl->reginfo.lock_type=
            read_lock_type_for_table(thd, thd->lex, tables,
                                     some_routine_modifies_data);
      else
        tbl->reginfo.lock_type= tables->lock_type;
    }
  }

#ifdef WITH_WSREP
  if (WSREP(thd)                                       &&
      wsrep_replicate_myisam                           &&
      (*start)                                         &&
      (*start)->table                                  &&
      (*start)->table->file->ht == myisam_hton         &&
      wsrep_thd_is_local(thd)                          &&
      !is_stat_table(&(*start)->db, &(*start)->alias)  &&
      thd->get_command() != COM_STMT_PREPARE           &&
      !thd->stmt_arena->is_stmt_prepare()              &&
      ((thd->lex->sql_command == SQLCOM_INSERT         ||
        thd->lex->sql_command == SQLCOM_INSERT_SELECT  ||
        thd->lex->sql_command == SQLCOM_REPLACE        ||
        thd->lex->sql_command == SQLCOM_REPLACE_SELECT ||
        thd->lex->sql_command == SQLCOM_UPDATE         ||
        thd->lex->sql_command == SQLCOM_UPDATE_MULTI   ||
        thd->lex->sql_command == SQLCOM_LOAD           ||
        thd->lex->sql_command == SQLCOM_DELETE)))
  {
      wsrep_before_rollback(thd, true);
      wsrep_after_rollback(thd, true);
      wsrep_after_statement(thd);
      WSREP_TO_ISOLATION_BEGIN(NULL, NULL, (*start));
  }
#endif /* WITH_WSREP */

error:
#ifdef WITH_WSREP
wsrep_error_label:
#endif
  THD_STAGE_INFO(thd, stage_after_opening_tables);
  thd_proc_info(thd, 0);

  if (unlikely(error) && *table_to_open)
  {
    (*table_to_open)->table= NULL;
  }
  DBUG_PRINT("open_tables", ("returning: %d", (int) error));
  DBUG_RETURN(error);
}


lock_table_names(THD *thd, const DDL_options_st &options,
                 TABLE_LIST *tables_start, TABLE_LIST *tables_end,
                 ulong lock_wait_timeout, uint flags)
{
  MDL_request_list mdl_requests;
  TABLE_LIST *table;
  MDL_request global_request;
  MDL_savepoint mdl_savepoint;
  DBUG_ENTER("lock_table_names");

  DBUG_ASSERT(!thd->locked_tables_mode);

  for (table= tables_start; table && table != tables_end;
       table= table->next_global)
  {
    DBUG_PRINT("info", ("mdl_request.type: %d  open_type: %d",
                        table->mdl_request.type, table->open_type));
    if (table->mdl_request.type < MDL_SHARED_UPGRADABLE ||
        table->mdl_request.type == MDL_SHARED_READ_ONLY ||
        table->open_type == OT_TEMPORARY_ONLY ||
        (table->open_type == OT_TEMPORARY_OR_BASE && is_temporary_table(table)))
    {
      continue;
    }

    /* Write lock on normal tables is not allowed in a read only transaction. */
    if (thd->tx_read_only)
    {
      my_error(ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION, MYF(0));
      DBUG_RETURN(true);
    }

    /* Scoped locks: Take intention exclusive locks on all involved schemas. */
    if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
    {
      MDL_request *schema_request= new (thd->mem_root) MDL_request;
      if (schema_request == NULL)
        DBUG_RETURN(TRUE);
      schema_request->init(MDL_key::SCHEMA, table->db.str, "",
                           MDL_INTENTION_EXCLUSIVE,
                           MDL_TRANSACTION);
      mdl_requests.push_front(schema_request);
    }

    mdl_requests.push_front(&table->mdl_request);
  }

  if (mdl_requests.is_empty())
    DBUG_RETURN(FALSE);

  if (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)
  {
    DBUG_RETURN(thd->mdl_context.acquire_locks(&mdl_requests,
                                               lock_wait_timeout) ||
                upgrade_lock_if_not_exists(thd, options, tables_start,
                                           lock_wait_timeout));
  }

  /* Protect this statement against concurrent BACKUP STAGE or FTWRL. */
  if (thd->has_read_only_protection())
    DBUG_RETURN(true);

  global_request.init(MDL_key::BACKUP, "", "", MDL_BACKUP_DDL, MDL_STATEMENT);
  mdl_savepoint= thd->mdl_context.mdl_savepoint();

  while (!thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout) &&
         !upgrade_lock_if_not_exists(thd, options, tables_start,
                                     lock_wait_timeout) &&
         !thd->mdl_context.try_acquire_lock(&global_request))
  {
    if (global_request.ticket)
    {
      thd->mdl_backup_ticket= global_request.ticket;
      DBUG_RETURN(false);
    }

    /*
      There is ongoing or pending BACKUP STAGE or FTWRL.
      Wait until it finishes and re-try.
    */
    thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
    if (thd->mdl_context.acquire_lock(&global_request, lock_wait_timeout))
      break;
    thd->mdl_context.rollback_to_savepoint(mdl_savepoint);

    /* Reset tickets for all acquired locks */
    global_request.ticket= 0;
    MDL_request_list::Iterator it(mdl_requests);
    while (auto mdl_request= it++)
      mdl_request->ticket= 0;
  }
  DBUG_RETURN(true);
}


static void mark_used_tables_as_free_for_reuse(THD *thd, TABLE *table)
{
  DBUG_ENTER("mark_used_tables_as_free_for_reuse");
  for (; table ; table= table->next)
  {
    DBUG_ASSERT(table->pos_in_locked_tables == NULL ||
                table->pos_in_locked_tables->table == table);
    if (table->query_id == thd->query_id)
    {
      table->query_id= 0;
      table->file->ha_reset();
    }
    else if (table->file->check_table_binlog_row_based_done)
      table->file->clear_cached_table_binlog_row_based_flag();
  }
  DBUG_VOID_RETURN;
}


bool close_cached_tables(THD *thd, TABLE_LIST *tables,
                         bool wait_for_refresh, ulong timeout)
{
  DBUG_ENTER("close_cached_tables");
  DBUG_ASSERT(thd || (!wait_for_refresh && !tables));
  DBUG_ASSERT(wait_for_refresh || !tables);

  if (!tables)
  {
    /* Free tables that are not used */
    purge_tables(false);
    if (!wait_for_refresh)
      DBUG_RETURN(false);
  }

  DBUG_PRINT("info", ("open table definitions: %d",
                      (int) tdc_records()));

  if (thd->locked_tables_mode)
  {
    /*
      If we are under LOCK TABLES, we need to reopen the tables without
      opening a door for any concurrent threads to sneak in and get
      lock on our tables. To achieve this we use exclusive metadata
      locks.
    */
    TABLE_LIST *tables_to_reopen= (tables ? tables :
                                  thd->locked_tables_list.locked_tables());
    bool result= false;

    /* close open HANDLER for this thread to allow table to be closed */
    mysql_ha_flush_tables(thd, tables_to_reopen);

    for (TABLE_LIST *table_list= tables_to_reopen; table_list;
         table_list= table_list->next_global)
    {
      int err;
      /* A check that the table was locked for write is done by the caller. */
      TABLE *table= find_table_for_mdl_upgrade(thd, table_list->db.str,
                                            table_list->table_name.str, &err);

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

      if (thd->mdl_context.upgrade_shared_lock(table->mdl_ticket, MDL_EXCLUSIVE,
                                               timeout))
      {
        result= true;
        break;
      }
      table->file->extra(HA_EXTRA_PREPARE_FOR_FORCED_CLOSE);
      close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED, NULL);
    }
    /*
      No other thread has the locked tables open; reopen them and get the
      old locks. This should always succeed (unless some external process
      has removed the tables)
    */
    if (thd->locked_tables_list.reopen_tables(thd, false))
      result= true;

    /*
      Since downgrade_lock() won't do anything with shared
      metadata lock it is much simpler to go through all open tables rather
      than picking only those tables that were flushed.
    */
    for (TABLE *tab= thd->open_tables; tab; tab= tab->next)
      tab->mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);

    DBUG_RETURN(result);
  }
  else if (tables)
  {
    /*
      Get an explicit MDL lock for all requested tables to ensure they are
      not used by any other thread
    */
    MDL_request_list mdl_requests;

    DBUG_PRINT("info", ("Waiting for other threads to close their open tables"));
    DEBUG_SYNC(thd, "after_flush_unlock");

    /* close open HANDLER for this thread to allow table to be closed */
    mysql_ha_flush_tables(thd, tables);

    for (TABLE_LIST *table= tables; table; table= table->next_local)
    {
      MDL_request *mdl_request= new (thd->mem_root) MDL_request;
      if (mdl_request == NULL)
        DBUG_RETURN(true);
      mdl_request->init(&table->mdl_request.key, MDL_EXCLUSIVE, MDL_STATEMENT);
      mdl_requests.push_front(mdl_request);
    }

    if (thd->mdl_context.acquire_locks(&mdl_requests, timeout))
      DBUG_RETURN(true);

    for (TABLE_LIST *table= tables; table; table= table->next_local)
      tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db.str,
                       table->table_name.str, false);
  }
  DBUG_RETURN(false);
}


static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
{
  DBUG_ENTER("update_field_dependencies");
  if (should_mark_column(thd->column_usage))
  {
    /*
      We always want to register the used keys, as the column bitmap may have
      been set for all fields (for example for view).
    */
    table->covering_keys.intersect(field->part_of_key);

    if (thd->column_usage == MARK_COLUMNS_READ)
    {
      if (table->mark_column_with_deps(field))
        DBUG_VOID_RETURN; // Field was already marked
    }
    else
    {
      if (bitmap_fast_test_and_set(table->write_set, field->field_index))
      {
        DBUG_PRINT("warning", ("Found duplicated field"));
        thd->dup_field= field;
        DBUG_VOID_RETURN;
      }
    }

    table->used_fields++;
  }
  if (table->get_fields_in_item_tree)
    field->flags|= GET_FIXED_FIELDS_FLAG;
  DBUG_VOID_RETURN;
}


insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
	      const char *table_name, List_iterator<Item> *it,
              bool any_privileges, uint *hidden_bit_fields)
{
  Field_iterator_table_ref field_iterator;
  bool found;
  char name_buff[SAFE_NAME_LEN+1];
  DBUG_ENTER("insert_fields");
  DBUG_PRINT("arena", ("stmt arena: %p",thd->stmt_arena));

  if (db_name && lower_case_table_names)
  {
    /*
      convert database to lower case for comparison
      We can't do this in Item_field as this would change the
      'name' of the item which may be used in the select list
    */
    strmake_buf(name_buff, db_name);
    my_casedn_str(files_charset_info, name_buff);
    db_name= name_buff;
  }

  found= FALSE;

  /*
    If table names are qualified, then loop over all tables used in the query,
    else treat natural joins as leaves and do not iterate over their underlying
    tables.
  */
  for (TABLE_LIST *tables= (table_name ? context->table_list :
                            context->first_name_resolution_table);
       tables;
       tables= (table_name ? tables->next_local :
                tables->next_name_resolution_table)
       )
  {
    Field *field;
    TABLE *table= tables->table;

    DBUG_ASSERT(tables->is_leaf_for_name_resolution());

    if ((table_name && my_strcasecmp(table_alias_charset, table_name,
                                     tables->alias.str)) ||
        (db_name && strcmp(tables->db.str, db_name)))
      continue;

#ifndef NO_EMBEDDED_ACCESS_CHECKS
    /*
       Ensure that we have access rights to all fields to be inserted
       the table 'tables'. Under some circumstances, this check may be skipped.

       The check is skipped in the following cases:

       - any_privileges is true

       - the table is a derived table

       - the table is a view with SELECT privilege

       - the table is a base table with SELECT privilege
    */
    if (!any_privileges &&
        !tables->is_derived() &&
        !(tables->is_view() && (tables->grant.privilege & SELECT_ACL)) &&
        !(table && (table->grant.privilege & SELECT_ACL)))
    {
      field_iterator.set(tables);
      if (check_grant_all_columns(thd, SELECT_ACL, &field_iterator))
        DBUG_RETURN(TRUE);
    }
#endif

    /*
      Update the tables used in the query based on the referenced fields. For
      views and natural joins this update is performed inside the loop below.
    */
    if (table)
    {
      thd->lex->used_tables|= table->map;
      thd->lex->current_select->select_list_tables|= table->map;
    }

    /*
      Initialize a generic field iterator for the current table reference.
      Notice that it is guaranteed that this iterator will iterate over the
      fields of a single table reference, because 'tables' is a leaf (for
      name resolution purposes).
    */
    field_iterator.set(tables);

    for (; !field_iterator.end_of_fields(); field_iterator.next())
    {
      /*
        field() is always NULL for views (see, e.g. Field_iterator_view or
        Field_iterator_natural_join).
        But view fields can never be invisible.
      */
      if ((field= field_iterator.field()) && field->invisible != VISIBLE)
        continue;

      Item *item;

      if (!(item= field_iterator.create_item(thd)))
        DBUG_RETURN(TRUE);

      /* cache the table for the Item_fields inserted by expanding stars */
      if (item->type() == Item::FIELD_ITEM && tables->cacheable_table)
        ((Item_field *)item)->cached_table= tables;

      if (!found)
      {
        found= TRUE;
        it->replace(item); /* Replace '*' with the first found item. */
      }
      else
        it->after(item);   /* Add 'item' to the SELECT list. */

      if (item->type() == Item::FIELD_ITEM && item->field_type() == MYSQL_TYPE_BIT)
        (*hidden_bit_fields)++;

#ifndef NO_EMBEDDED_ACCESS_CHECKS
      /*
        Set privilege information for the fields of newly created views.
        We have that (any_priviliges == TRUE) if and only if we are creating
        a view. In the time of view creation we can't use the MERGE algorithm,
        therefore if 'tables' is itself a view, it is represented by a
        temporary table. Thus in this case we can be sure that 'item' is an
        Item_field.
      */
      if (any_privileges && !tables->is_with_table() && !tables->is_derived())
      {
        DBUG_ASSERT((tables->field_translation == NULL && table) ||
                    tables->is_natural_join);
        DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
        Item_field *fld= (Item_field*) item;
        const char *field_table_name= field_iterator.get_table_name();

        if (!tables->schema_table &&
            !(fld->have_privileges=
              (get_column_grant(thd, field_iterator.grant(),
                                field_iterator.get_db_name(),
                                field_table_name, fld->field_name.str) &
               VIEW_ANY_ACL)))
        {
          my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), "ANY",
                   thd->security_ctx->priv_user,
                   thd->security_ctx->host_or_ip,
                   field_table_name);
          DBUG_RETURN(TRUE);
        }
      }
#endif

      if ((field= field_iterator.field()))
      {
        field->table->mark_column_with_deps(field);
        if (table)
          table->covering_keys.intersect(field->part_of_key);
        if (tables->is_natural_join)
        {
          TABLE *field_table;
          /*
            In this case we are sure that the column ref will not be created
            because it was already created and stored with the natural join.
          */
          Natural_join_column *nj_col;
          if (!(nj_col= field_iterator.get_natural_column_ref()))
            DBUG_RETURN(TRUE);
          DBUG_ASSERT(nj_col->table_field);
          field_table= nj_col->table_ref->table;
          if (field_table)
          {
            thd->lex->used_tables|= field_table->map;
            thd->lex->current_select->select_list_tables|=
              field_table->map;
            field_table->covering_keys.intersect(field->part_of_key);
            field_table->used_fields++;
          }
        }
      }
      else
        thd->lex->used_tables|= item->used_tables();
      thd->lex->current_select->cur_pos_in_select_list++;
    }
    /*
      In case of stored tables, all fields are considered as used,
      while in the case of views, the fields considered as used are the
      ones marked in setup_tables during fix_fields of view columns.
      For NATURAL joins, used_tables is updated in the IF above.
    */
    if (table)
      table->used_fields= table->s->fields;
  }
  if (found)
    DBUG_RETURN(FALSE);

  /*
    TODO: in the case when we skipped all columns because there was a
    qualified '*', and all columns were coalesced, we have to give a more
    meaningful message than ER_BAD_TABLE_ERROR.
  */
  if (!table_name)
    my_error(ER_NO_TABLES_USED, MYF(0));
  else if (!db_name && !thd->db.str)
    my_error(ER_NO_DB_ERROR, MYF(0));
  else
  {
    char name[FN_REFLEN];
    my_snprintf(name, sizeof(name), "%s.%s",
                db_name ? db_name : thd->get_db(), table_name);
    my_error(ER_BAD_TABLE_ERROR, MYF(0), name);
  }

  DBUG_RETURN(TRUE);
}