bool Item_func_like::find_selective_predicates_list_processor(void *arg)
{
  find_selective_predicates_list_processor_data *data=
    (find_selective_predicates_list_processor_data *) arg;
  if (use_sampling && used_tables() == data->table->map)
  {
    THD *thd= data->table->in_use;
    COND_STATISTIC *stat;
    Item *arg0;
    if (!(stat= (COND_STATISTIC *) thd->alloc(sizeof(COND_STATISTIC))))
      return TRUE;
    stat->cond= this;
    arg0= args[0]->real_item();
    if (args[1]->const_item() && arg0->type() == FIELD_ITEM)
      stat->field_arg= ((Item_field *)arg0)->field;
    else
      stat->field_arg= NULL;
    data->list.push_back(stat, thd->mem_root);
  }
  return FALSE;
}


MDEV-26402: A SEGV in Item_field::used_tables/update_depend_map_for_order...

When doing condition pushdown from HAVING into WHERE,
Item_equal::create_pushable_equalities() calls
item->set_extraction_flag(IMMUTABLE_FL) for constant items.
Then, Item::cleanup_excluding_immutables_processor() checks for this flag
to see if it should call item->cleanup() or leave the item as-is.

The failure happens when a constant item has a non-constant one inside it,
like:

   (tbl.col=0 AND impossible_cond)

item->walk(cleanup_excluding_immutables_processor) works in a bottom-up
way so it
1. will call Item_func_eq(tbl.col=0)->cleanup()
2. will not call Item_cond_and->cleanup (as the AND is constant)

This creates an item tree where a fixed Item has an un-fixed Item inside
it which eventually causes an assertion failure.

Fixed by introducing this rule: instead of just calling

  item->set_extraction_flag(IMMUTABLE_FL);

we call Item::walk() to set the flag for all sub-items of the item.

Item_bool_rowready_func2* Lt_creator::create_swap(THD *thd, Item *a, Item *b) const
{
  return new(thd->mem_root) Item_func_gt(thd, b, a);
}

MariaDB Server v10.7 and below was discovered to contain a segmentation fault via the component Item_field::used_tables/update_depend_map_for_order.


  Item_default_specification(THD *thd)
   :Item_contextually_typed_value_specification(thd)
  { }


  bool val_native_with_conversion_from_item(THD *thd, Item *item, Native *to,
                                            const Type_handler *handler)
  {
    DBUG_ASSERT(is_fixed());
    return null_value= item->val_native_with_conversion(thd, to, handler);
  }


  const MYSQL_TIME *const_ptr_mysql_time() const
  { return can_return_const_value(TIME_RESULT) ? &value.time : NULL; }


    void swap(PValue &other)
    {
      Type_handler_hybrid_field_type::swap(other);
      PValue_simple::swap(other);
      m_decimal.swap(other.m_decimal);
      m_string.swap(other.m_string);
      m_string_ptr.swap(other.m_string_ptr);
    }


inline void Item_func_case::print_when_then_arguments(String *str,
                                                      enum_query_type
                                                      query_type,
                                                      Item **items, uint count)
{
  for (uint i= 0; i < count; i++)
  {
    str->append(STRING_WITH_LEN("when "));
    items[i]->print(str, query_type);
    str->append(STRING_WITH_LEN(" then "));
    items[i + count]->print(str, query_type);
    str->append(' ');
  }
}


  bool set_value(THD *thd, const Type_all_attributes *attr,
                 const st_value *val, const Type_handler *h)
  {
    value.set_handler(h); // See comments in set_param_func()
    return h->Item_param_set_from_value(thd, this, attr, val);
  }


void set_maybe_null(bool maybe_null_arg) { maybe_null= maybe_null_arg; }


  void process_error(THD *thd)
  {
    if (context)
      context->process_error(thd);
  }


void Item_in_optimizer::get_cache_parameters(List<Item> &parameters)
{
  DBUG_ASSERT(fixed);
  /* Add left expression to the list of the parameters of the subquery */
  if (!invisible_mode())
  {
    if (args[0]->cols() == 1)
      parameters.add_unique(args[0], &cmp_items);
    else
    {
      for (uint i= 0; i < args[0]->cols(); i++)
      {
        parameters.add_unique(args[0]->element_index(i), &cmp_items);
      }
    }
  }
  args[1]->get_cache_parameters(parameters);
}


int Arg_comparator::set_cmp_func(Item_func_or_sum *owner_arg,
                                 Item **a1, Item **a2)
{
  owner= owner_arg;
  set_null= set_null && owner_arg;
  a= a1;
  b= a2;
  Item *tmp_args[2]= {*a1, *a2};
  Type_handler_hybrid_field_type tmp;
  if (tmp.aggregate_for_comparison(owner_arg->func_name(), tmp_args, 2, false))
  {
    DBUG_ASSERT(current_thd->is_error());
    return 1;
  }
  m_compare_handler= tmp.type_handler();
  return m_compare_handler->set_comparator_func(this);
}


void Item_func_truth::print(String *str, enum_query_type query_type)
{
  args[0]->print_parenthesised(str, query_type, precedence());
  str->append(STRING_WITH_LEN(" is "));
  if (! affirmative)
    str->append(STRING_WITH_LEN("not "));
  if (value)
    str->append(STRING_WITH_LEN("true"));
  else
    str->append(STRING_WITH_LEN("false"));
}


longlong Item_func_xor::val_int()
{
  DBUG_ASSERT(fixed == 1);
  int result= 0;
  null_value= false;
  for (uint i= 0; i < arg_count; i++)
  {
    result^= (args[i]->val_int() != 0);
    if (args[i]->null_value)
    {
      null_value= true;
      return 0;
    }
  }
  return result;
}


Item_bool_rowready_func2* Ne_creator::create_swap(THD *thd, Item *a, Item *b) const
{
  return new(thd->mem_root) Item_func_ne(thd, b, a);
}


  int save_in_field(Field *field, bool no_conversions)
  {
    Timestamp_or_zero_datetime_native native(m_value, decimals);
    return native.save_in_field(field, decimals);
  }


double val_real() { return ulonglong2double((ulonglong)value); }


int Arg_comparator::compare_e_native()
{
  THD *thd= current_thd;
  bool res1= (*a)->val_native_with_conversion(thd, &m_native1,
                                              compare_type_handler());
  bool res2= (*b)->val_native_with_conversion(thd, &m_native2,
                                              compare_type_handler());
  if (res1 || res2)
    return MY_TEST(res1 == res2);
  return MY_TEST(compare_type_handler()->cmp_native(m_native1, m_native2) == 0);
}


  void print(String *str, enum_query_type query_type)
  {
    str->append(STRING_WITH_LEN("default"));
  }


  Tmp_field_param(bool group,
                  bool modify_item,
                  bool table_cant_handle_bit_fields,
                  bool make_copy_field)
   :m_group(group),
    m_modify_item(modify_item),
    m_table_cant_handle_bit_fields(table_cant_handle_bit_fields),
    m_make_copy_field(make_copy_field)
  { }


  my_decimal *val_decimal(my_decimal *to)
  {
    return to_datetime(current_thd).to_decimal(to);
  }


  Item_cache(THD *thd, const Type_handler *handler):
    Item(thd),
    Type_handler_hybrid_field_type(handler),
    example(0), cached_field(0),
    value_cached(0),
    used_table_map(0)
  {
    maybe_null= 1;
    null_value= 1;
    null_value_inside= true;
  }


  Longlong_hybrid_null to_longlong_hybrid_null()
  {
    return Longlong_hybrid_null(to_longlong_null(), unsigned_flag);
  }


  const MYSQL_TIME *const_ptr_mysql_time() const
  {
    return cached_time.get_mysql_time();
  }


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


  bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
  {
    DBUG_ASSERT(0); // never should be called
    return null_value= true;
  }


uint32 max_display_length() const { return field->max_display_length(); }


void Item_func_like::turboBM_compute_bad_character_shifts()
{
  int *i;
  int *end = bmBc + alphabet_size;
  int j;
  const int plm1 = pattern_len - 1;
  CHARSET_INFO	*cs= cmp_collation.collation;

  for (i = bmBc; i < end; i++)
    *i = pattern_len;

  if (!cs->sort_order)
  {
    for (j = 0; j < plm1; j++)
      bmBc[(uint) (uchar) pattern[j]] = plm1 - j;
  }
  else
  {
    for (j = 0; j < plm1; j++)
      bmBc[(uint) likeconv(cs,pattern[j])] = plm1 - j;
  }
}


  longlong val_int()
  {
    return longlong_from_hex_hybrid(str_value.ptr(), str_value.length());
  }


  String *val_str(String *to)
  {
    return update_null() ? 0 : cached_time.to_string(to);
  }


  bool val_native(THD *thd, Native *to)
  {
    if (check_null_ref())
      return true;
    return Item_direct_ref::val_native(thd, to);
  }


Item *Item_func_not_all::neg_transformer(THD *thd)
{
  /* "NOT (e $cmp$ ALL (SELECT ...)) -> e $rev_cmp$" ANY (SELECT ...) */
  Item_func_nop_all *new_item= new (thd->mem_root) Item_func_nop_all(thd, args[0]);
  Item_allany_subselect *allany= (Item_allany_subselect*)args[0];
  allany->all= !allany->all;
  allany->create_comp_func(TRUE);
  allany->upper_item= new_item;
  return new_item;
}


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


bool is_null() const { return m_type == DYN_COL_NULL; }


  String *val_str(String*)
  {
    return (String*) &str_value;
  }


bool Item_func_like::turboBM_matches(const char* text, int text_len) const
{
  int bcShift;
  int turboShift;
  int shift = pattern_len;
  int j     = 0;
  int u     = 0;
  CHARSET_INFO	*cs= cmp_collation.collation;

  const int plm1=  pattern_len - 1;
  const int tlmpl= text_len - pattern_len;

  /* Searching */
  if (!cs->sort_order)
  {
    while (j <= tlmpl)
    {
      int i= plm1;
      while (i >= 0 && pattern[i] == text[i + j])
      {
	i--;
	if (i == plm1 - shift)
	  i-= u;
      }
      if (i < 0)
	return 1;

      const int v= plm1 - i;
      turboShift = u - v;
      bcShift    = bmBc[(uint) (uchar) text[i + j]] - plm1 + i;
      shift      = MY_MAX(turboShift, bcShift);
      shift      = MY_MAX(shift, bmGs[i]);
      if (shift == bmGs[i])
	u = MY_MIN(pattern_len - shift, v);
      else
      {
	if (turboShift < bcShift)
	  shift = MY_MAX(shift, u + 1);
	u = 0;
      }
      j+= shift;
    }
    return 0;
  }
  else
  {
    while (j <= tlmpl)
    {
      int i= plm1;
      while (i >= 0 && likeconv(cs,pattern[i]) == likeconv(cs,text[i + j]))
      {
	i--;
	if (i == plm1 - shift)
	  i-= u;
      }
      if (i < 0)
	return 1;

      const int v= plm1 - i;
      turboShift = u - v;
      bcShift    = bmBc[(uint) likeconv(cs, text[i + j])] - plm1 + i;
      shift      = MY_MAX(turboShift, bcShift);
      shift      = MY_MAX(shift, bmGs[i]);
      if (shift == bmGs[i])
	u = MY_MIN(pattern_len - shift, v);
      else
      {
	if (turboShift < bcShift)
	  shift = MY_MAX(shift, u + 1);
	u = 0;
      }
      j+= shift;
    }
    return 0;
  }
}


void Item_func_in::fix_after_pullout(st_select_lex *new_parent, Item **ref,
                                     bool merge)
{
  /* This will re-calculate attributes of the arguments */
  Item_func_opt_neg::fix_after_pullout(new_parent, ref, merge);
  /* Then, re-calculate not_null_tables_cache according to our special rules */
  eval_not_null_tables(NULL);
}


bool Item_func_ifnull::native_op(THD *thd, Native *to)
{
  DBUG_ASSERT(fixed == 1);
  if (!val_native_with_conversion_from_item(thd, args[0], to, type_handler()))
    return false;
  return val_native_with_conversion_from_item(thd, args[1], to, type_handler());
}


  longlong val_int()
  {
    if (value <= (double) LONGLONG_MIN)
    {
       return LONGLONG_MIN;
    }
    else if (value >= (double) (ulonglong) LONGLONG_MAX)
    {
      return LONGLONG_MAX;
    }
    return (longlong) rint(value);
  }


bool Predicant_to_list_comparator::make_unique_cmp_items(THD *thd,
                                                         CHARSET_INFO *cs)
{
  for (uint i= 0; i < m_comparator_count; i++)
  {
    if (m_comparators[i].m_handler &&                   // Skip implicit NULLs
        m_comparators[i].m_handler_index == i && // Skip non-unuque
        !(m_comparators[i].m_cmp_item=
          m_comparators[i].m_handler->make_cmp_item(thd, cs)))
       return true;
  }
  return false;
}


longlong val_int() { return cached_time.to_longlong(); }


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


void Item_func_case::reorder_args(uint start)
{
  /*
    Reorder args, to have at first the optional CASE expression, then all WHEN
    expressions, then all THEN expressions. And the optional ELSE expression
    at the end.

    We reorder an even number of arguments, starting from start.
  */
  uint count = (arg_count - start) / 2;
  const size_t size= sizeof(Item*) * count * 2;
  Item **arg_buffer= (Item **)my_safe_alloca(size);
  memcpy(arg_buffer, &args[start], size);
  for (uint i= 0; i < count; i++)
  {
    args[start + i]= arg_buffer[i*2];
    args[start + i + count]= arg_buffer[i*2 + 1];
  }
  my_safe_afree(arg_buffer, size);
}


Item_equal::excl_dep_on_grouping_fields(st_select_lex *sel)
{
  Item_equal_fields_iterator it(*this);
  Item *item;

  while ((item=it++))
  {
    if (item->excl_dep_on_grouping_fields(sel))
    {
      set_extraction_flag(FULL_EXTRACTION_FL);
      return true;
    }
  }
  return false;
}


longlong Item_func_coalesce::int_op()
{
  DBUG_ASSERT(fixed == 1);
  null_value=0;
  for (uint i=0 ; i < arg_count ; i++)
  {
    longlong res=args[i]->val_int();
    if (!args[i]->null_value)
      return res;
  }
  null_value=1;
  return 0;
}


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


  const Item_const *get_item_const() const
  {
    switch (state) {
    case SHORT_DATA_VALUE:
    case LONG_DATA_VALUE:
    case NULL_VALUE:
      return this;
    case IGNORE_VALUE:
    case DEFAULT_VALUE:
    case NO_VALUE:
      break;
    }
    return NULL;
  }


in_longlong::in_longlong(THD *thd, uint elements)
  :in_vector(thd, elements, sizeof(packed_longlong),
             (qsort2_cmp) cmp_longlong, 0)
{}


  my_decimal *val_decimal(my_decimal *to)
  {
    return update_null() ? NULL : cached_time.to_decimal(to);
  }


Item *Item_func_isnull::neg_transformer(THD *thd)
{
  Item *item= new (thd->mem_root) Item_func_isnotnull(thd, args[0]);
  return item;
}


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


static bool convert_const_to_int(THD *thd, Item_field *field_item,
                                  Item **item)
{
  Field *field= field_item->field;
  int result= 0;

  /*
    We don't need to convert an integer to an integer,
    pretend it's already converted.

    But we still convert it if it is compared with a Field_year,
    as YEAR(2) may change the value of an integer when converting it
    to an integer (say, 0 to 70).
  */
  if ((*item)->cmp_type() == INT_RESULT &&
      field_item->field_type() != MYSQL_TYPE_YEAR)
    return 1;

  if ((*item)->const_item() && !(*item)->is_expensive())
  {
    TABLE *table= field->table;
    Sql_mode_save sql_mode(thd);
    Check_level_instant_set check_level_save(thd, CHECK_FIELD_IGNORE);
    MY_BITMAP *old_maps[2] = { NULL, NULL };
    ulonglong UNINIT_VAR(orig_field_val); /* original field value if valid */

    /* table->read_set may not be set if we come here from a CREATE TABLE */
    if (table && table->read_set)
      dbug_tmp_use_all_columns(table, old_maps,
                               &table->read_set, &table->write_set);
    /* For comparison purposes allow invalid dates like 2000-01-32 */
    thd->variables.sql_mode= (thd->variables.sql_mode & ~MODE_NO_ZERO_DATE) |
                             MODE_INVALID_DATES;

    /*
      Store the value of the field/constant because the call to save_in_field
      below overrides that value. Don't save field value if no data has been
      read yet.
    */
    bool save_field_value= (field_item->const_item() ||
                            !(field->table->status & STATUS_NO_RECORD));
    if (save_field_value)
      orig_field_val= field->val_int();
    if (!(*item)->save_in_field(field, 1) && !field->is_null())
    {
      int field_cmp= 0;
      // If item is a decimal value, we must reject it if it was truncated.
      if (field->type() == MYSQL_TYPE_LONGLONG)
      {
        field_cmp= stored_field_cmp_to_item(thd, field, *item);
        DBUG_PRINT("info", ("convert_const_to_int %d", field_cmp));
      }

      if (0 == field_cmp)
      {
        Item *tmp= new (thd->mem_root) Item_int_with_ref(thd, field->val_int(), *item,
                                         MY_TEST(field->flags & UNSIGNED_FLAG));
        if (tmp)
          thd->change_item_tree(item, tmp);
        result= 1;					// Item was replaced
      }
    }
    /* Restore the original field value. */
    if (save_field_value)
    {
      result= field->store(orig_field_val, TRUE);
      /* orig_field_val must be a valid value that can be restored back. */
      DBUG_ASSERT(!result);
    }
    if (table && table->read_set)
      dbug_tmp_restore_column_maps(&table->read_set, &table->write_set, old_maps);
  }
  return result;
}


bool Item_func_coalesce::time_op(THD *thd, MYSQL_TIME *ltime)
{
  DBUG_ASSERT(fixed == 1);
  for (uint i= 0; i < arg_count; i++)
  {
    if (!Time(thd, args[i]).copy_to_mysql_time(ltime))
      return (null_value= false);
  }
  return (null_value= true);
}


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


longlong val_int() { return decimal_value.to_longlong(unsigned_flag); }


void join(const Item *item) { m_with_subquery|= item->with_subquery(); }


virtual const my_decimal *const_ptr_my_decimal() const { return NULL; }


virtual With_sum_func_cache* get_with_sum_func_cache() { return NULL; }


void Item_func_like::turboBM_compute_good_suffix_shifts(int *suff)
{
  turboBM_compute_suffixes(suff);

  int *end = bmGs + pattern_len;
  int *k;
  for (k = bmGs; k < end; k++)
    *k = pattern_len;

  int tmp;
  int i;
  int j          = 0;
  const int plm1 = pattern_len - 1;
  for (i = plm1; i > -1; i--)
  {
    if (suff[i] == i + 1)
    {
      for (tmp = plm1 - i; j < tmp; j++)
      {
	int *tmp2 = bmGs + j;
	if (*tmp2 == pattern_len)
	  *tmp2 = tmp;
      }
    }
  }

  int *tmp2;
  for (tmp = plm1 - i; j < tmp; j++)
  {
    tmp2 = bmGs + j;
    if (*tmp2 == pattern_len)
      *tmp2 = tmp;
  }

  tmp2 = bmGs + plm1;
  for (i = 0; i <= pattern_len - 2; i++)
    *(tmp2 - suff[i]) = plm1 - i;
}


  bool val_native(THD *thd, Native *to)
  {
    return Item_param::type_handler()->Item_param_val_native(thd, this, to);
  }


Item *Item_func_gt::negated_item(THD *thd) /* a > b  ->  a <= b */
{
  return new (thd->mem_root) Item_func_le(thd, args[0], args[1]);
}


Item_equal::Item_equal(THD *thd, const Type_handler *handler,
                       Item *f1, Item *f2, bool with_const_item):
  Item_bool_func(thd), eval_item(0), cond_false(0), cond_true(0),
  context_field(NULL), link_equal_fields(FALSE),
  m_compare_handler(handler),
  m_compare_collation(f2->collation.collation)
{
  const_item_cache= 0;
  with_const= with_const_item;
  equal_items.push_back(f1, thd->mem_root);
  equal_items.push_back(f2, thd->mem_root);
  upper_levels= NULL;
}


bool Item_equal::create_pushable_equalities(THD *thd,
                                            List<Item> *equalities,
                                            Pushdown_checker checker,
                                            uchar *arg,
                                            bool clone_const)
{
  Item *item;
  Item *left_item= NULL;
  Item *right_item = get_const();
  Item_equal_fields_iterator it(*this);

  while ((item=it++))
  {
    left_item= item;
    if (checker && !((item->*checker) (arg)))
      continue;
    break;
  }

  if (!left_item)
    return false;

  if (right_item)
  {
    Item_func_eq *eq= 0;
    Item *left_item_clone= left_item->build_clone(thd);
    Item *right_item_clone= !clone_const ?
                            right_item : right_item->build_clone(thd);
    if (!left_item_clone || !right_item_clone)
      return true;
    eq= new (thd->mem_root) Item_func_eq(thd,
                                         left_item_clone,
                                         right_item_clone);
    if (!eq ||  equalities->push_back(eq, thd->mem_root))
      return true;
    if (!clone_const)
    {
      /*
        Also set IMMUTABLE_FL for any sub-items of the right_item.
        This is needed to prevent Item::cleanup_excluding_immutables_processor
        from peforming cleanup of the sub-items and so creating an item tree
        where a fixed item has non-fixed items inside it.
      */
      int new_flag= IMMUTABLE_FL;
      right_item->walk(&Item::set_extraction_flag_processor, false,
                       (void*)&new_flag);
    }
  }

  while ((item=it++))
  {
    if (checker && !((item->*checker) (arg)))
      continue;
    Item_func_eq *eq= 0;
    Item *left_item_clone= left_item->build_clone(thd);
    Item *right_item_clone= item->build_clone(thd);
    if (!(left_item_clone && right_item_clone))
      return true;
    left_item_clone->set_item_equal(NULL);
    right_item_clone->set_item_equal(NULL);
    eq= new (thd->mem_root) Item_func_eq(thd,
                                         right_item_clone,
                                         left_item_clone);
    if (!eq || equalities->push_back(eq, thd->mem_root))
      return true;
  }
  return false;
}


  virtual table_map used_tables() const
  {
    return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT;
  }


virtual Item *remove_item_direct_ref() { return this; }


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


bool Item_func_between::val_int_cmp_int_finalize(longlong value,
                                                 longlong a,
                                                 longlong b)
{
  if (!args[1]->null_value && !args[2]->null_value)
    return (longlong) ((value >= a && value <= b) != negated);
  if (args[1]->null_value && args[2]->null_value)
    null_value= true;
  else if (args[1]->null_value)
    null_value= value <= b;			// not null if false range.
  else
    null_value= value >= a;
  return (longlong) (!null_value && negated);
}


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


  const Type_all_attributes *get_type_all_attributes_from_const() const
  { return this; }


  longlong val_int()
  {
    return m_value.to_datetime(current_thd).to_longlong();
  }


  longlong val_int()
  {
    return update_null() ? 0 : cached_time.to_longlong();
  }


  Item_string(THD *thd, const char *str, size_t length,
              CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
   :Item_literal(thd)
  {
    str_value.set_or_copy_aligned(str, length, cs);
    fix_and_set_name_from_value(thd, dv, Metadata(&str_value));
  }


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


  Item_cache(THD *thd):
    Item(thd),
    Type_handler_hybrid_field_type(&type_handler_string),
    example(0), cached_field(0),
    value_cached(0),
    used_table_map(0)
  {
    maybe_null= 1;
    null_value= 1;
    null_value_inside= true;
  }


bool Item_func_opt_neg::eq(const Item *item, bool binary_cmp) const
{
  /* Assume we don't have rtti */
  if (this == item)
    return 1;
  if (item->type() != FUNC_ITEM)
    return 0;
  Item_func *item_func=(Item_func*) item;
  if (arg_count != item_func->argument_count() ||
      functype() != item_func->functype())
    return 0;
  if (negated != ((Item_func_opt_neg *) item_func)->negated)
    return 0;
  return Item_args::eq(item_func, binary_cmp);
}


Item** Arg_comparator::cache_converted_constant(THD *thd_arg, Item **value,
                                                Item **cache_item,
                                                const Type_handler *handler)
{
  /*
    Don't need cache if doing context analysis only.
  */
  if (!thd_arg->lex->is_ps_or_view_context_analysis() &&
      (*value)->const_item() &&
      handler->type_handler_for_comparison() !=
      (*value)->type_handler_for_comparison())
  {
    Item_cache *cache= handler->Item_get_cache(thd_arg, *value);
    cache->setup(thd_arg, *value);
    *cache_item= cache;
    return cache_item;
  }
  return value;
}


Item *Item_cond_and::copy_andor_structure(THD *thd)
{
  Item_cond_and *item;
  if ((item= new (thd->mem_root) Item_cond_and(thd, this)))
    item->copy_andor_arguments(thd, this);
  return item;
}


cmp_item* cmp_item_row::make_same()
{
  return new cmp_item_row();
}


void Item_func_like::turboBM_compute_suffixes(int *suff)
{
  const int   plm1 = pattern_len - 1;
  int            f = 0;
  int            g = plm1;
  int *const splm1 = suff + plm1;
  CHARSET_INFO	*cs= cmp_collation.collation;

  *splm1 = pattern_len;

  if (!cs->sort_order)
  {
    int i;
    for (i = pattern_len - 2; i >= 0; i--)
    {
      int tmp = *(splm1 + i - f);
      if (g < i && tmp < i - g)
	suff[i] = tmp;
      else
      {
	if (i < g)
	  g = i; // g = MY_MIN(i, g)
	f = i;
	while (g >= 0 && pattern[g] == pattern[g + plm1 - f])
	  g--;
	suff[i] = f - g;
      }
    }
  }
  else
  {
    int i;
    for (i = pattern_len - 2; 0 <= i; --i)
    {
      int tmp = *(splm1 + i - f);
      if (g < i && tmp < i - g)
	suff[i] = tmp;
      else
      {
	if (i < g)
	  g = i; // g = MY_MIN(i, g)
	f = i;
	while (g >= 0 &&
	       likeconv(cs, pattern[g]) == likeconv(cs, pattern[g + plm1 - f]))
	  g--;
	suff[i] = f - g;
      }
    }
  }
}


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


void Item_equal::merge_into_list(THD *thd, List<Item_equal> *list,
                                 bool save_merged,
                                 bool only_intersected)
{
  Item_equal *item;
  List_iterator<Item_equal> it(*list);
  Item_equal *merge_into= NULL;
  while((item= it++))
  {
    if (!merge_into)
    {
      if (item->merge_with_check(thd, this, save_merged))
        merge_into= item;
    }
    else
    {
      if (merge_into->merge_with_check(thd, item, false))
        it.remove();
    }
  }
  if (!only_intersected && !merge_into)
    list->push_back(this, thd->mem_root);
}


int Arg_comparator::compare_int_unsigned()
{
  ulonglong val1= (*a)->val_int();
  if (!(*a)->null_value)
  {
    ulonglong val2= (*b)->val_int();
    if (!(*b)->null_value)
    {
      if (set_null)
        owner->null_value= 0;
      if (val1 < val2)	return -1;
      if (val1 == val2)   return 0;
      return 1;
    }
  }
  if (set_null)
    owner->null_value= 1;
  return -1;
}


  Item *remove_item_direct_ref()
  {
    *ref= (*ref)->remove_item_direct_ref();
    return this;
  }


  bool is_order_clause_position() const
  {
    return state == SHORT_DATA_VALUE &&
           type_handler()->is_order_clause_position_type();
  }


  const Type_handler *real_type_handler() const
  {
    // Should not be called, Item_blob is used for SHOW purposes only.
    DBUG_ASSERT(0);
    return &type_handler_varchar;
  }


void Item_func_between::fix_after_pullout(st_select_lex *new_parent,
                                          Item **ref, bool merge)
{
  /* This will re-calculate attributes of the arguments */
  Item_func_opt_neg::fix_after_pullout(new_parent, ref, merge);
  /* Then, re-calculate not_null_tables_cache according to our special rules */
  eval_not_null_tables(NULL);
}


  void set_typelib(TYPELIB *typelib)
  {
    // Non-field Items (e.g. hybrid functions) never have ENUM/SET types yet.
    DBUG_ASSERT(0);
  }


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


void Item_cond::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
                               List<Item> &fields, uint flags)
{
  List_iterator<Item> li(list);
  Item *item;
  while ((item= li++))
    item->split_sum_func2(thd, ref_pointer_array, fields, li.ref(),
                          flags | SPLIT_SUM_SKIP_REGISTERED);
}


void in_decimal::set(uint pos, Item *item)
{
  /* as far as 'item' is constant, we can store reference on my_decimal */
  my_decimal *dec= ((my_decimal *)base) + pos;
  dec->len= DECIMAL_BUFF_LENGTH;
  dec->fix_buffer_pointer();
  my_decimal *res= item->val_decimal(dec);
  /* if item->val_decimal() is evaluated to NULL then res == 0 */
  if (!item->null_value && res != dec)
    my_decimal2decimal(res, dec);
}


int Arg_comparator::compare_e_int_diff_signedness()
{
  longlong val1= (*a)->val_int();
  longlong val2= (*b)->val_int();
  if ((*a)->null_value || (*b)->null_value)
    return MY_TEST((*a)->null_value && (*b)->null_value);
  return (val1 >= 0) && MY_TEST(val1 == val2);
}


Item *in_string::create_item(THD *thd)
{
  return new (thd->mem_root) Item_string_for_in_vector(thd, collation);
}


  Item_cache_float(THD *thd)
   :Item_cache_real(thd, &type_handler_float)
  { }


  virtual bool send(Protocol *protocol, st_value *buffer)
  {
    return type_handler()->Item_send(this, protocol, buffer);
  }


bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; }


Item* Item_equal::get_first(JOIN_TAB *context, Item *field_item)
{
  Item_equal_fields_iterator it(*this);
  Item *item;
  if (!field_item)
    return (it++);
  Field *field= ((Item_field *) (field_item->real_item()))->field;

  /*
    Of all equal fields, return the first one we can use. Normally, this is the
    field which belongs to the table that is the first in the join order.

    There is one exception to this: When semi-join materialization strategy is
    used, and the given field belongs to a table within the semi-join nest, we
    must pick the first field in the semi-join nest.

    Example: suppose we have a join order:

       ot1 ot2  SJ-Mat(it1  it2  it3)  ot3

    and equality ot2.col = it1.col = it2.col
    If we're looking for best substitute for 'it2.col', we should pick it1.col
    and not ot2.col.

    eliminate_item_equal() also has code that deals with equality substitution
    in presence of SJM nests.
  */

  TABLE_LIST *emb_nest;
  if (context != NO_PARTICULAR_TAB)
    emb_nest= context->emb_sj_nest;
  else
    emb_nest= field->table->pos_in_table_list->embedding;

  if (emb_nest && emb_nest->sj_mat_info && emb_nest->sj_mat_info->is_used)
  {
    /*
      It's a field from an materialized semi-join. We can substitute it for
       - a constant item
       - a field from the same semi-join
       Find the first of such items:
    */
    while ((item= it++))
    {
      if (item->const_item() ||
          it.get_curr_field()->table->pos_in_table_list->embedding == emb_nest)
      {
        /*
          If we found given field then return NULL to avoid unnecessary
          substitution.
        */
        return (item != field_item) ? item : NULL;
      }
    }
  }
  else
  {
    /*
      The field is not in SJ-Materialization nest. We must return the first
      field in the join order. The field may be inside a semi-join nest, i.e
      a join order may look like this:

          SJ-Mat(it1  it2)  ot1  ot2

      where we're looking what to substitute ot2.col for. In this case we must
      still return it1.col, here's a proof why:

      First let's note that either it1.col or it2.col participates in
      subquery's IN-equality. It can't be otherwise, because materialization is
      only applicable to uncorrelated subqueries, so the only way we could
      infer "it1.col=ot1.col" is from the IN-equality. Ok, so IN-eqality has
      it1.col or it2.col on its inner side. it1.col is first such item in the
      join order, so it's not possible for SJ-Mat to be
      SJ-Materialization-lookup, it is SJ-Materialization-Scan. The scan part
      of this strategy will unpack value of it1.col=it2.col into it1.col
      (that's the first equal item inside the subquery), and we'll be able to
      get it from there. qed.
    */

    return equal_items.head();
  }
  // Shouldn't get here.
  DBUG_ASSERT(0);
  return NULL;
}


longlong Item_func_lt::val_int()
{
  DBUG_ASSERT(fixed == 1);
  int value= cmp.compare();
  return value < 0 && !null_value ? 1 : 0;
}


  virtual void update_null_value ()
  {
    return type_handler()->Item_update_null_value(this);
  }


bool Item_func_between::fix_length_and_dec_numeric(THD *thd)
{
  /* See the comment about the similar block in Item_bool_func2 */
  if (args[0]->real_item()->type() == FIELD_ITEM &&
      !thd->lex->is_ps_or_view_context_analysis())
  {
    Item_field *field_item= (Item_field*) (args[0]->real_item());
    if (field_item->field_type() ==  MYSQL_TYPE_LONGLONG ||
        field_item->field_type() ==  MYSQL_TYPE_YEAR)
    {
      const bool cvt_arg1= convert_const_to_int(thd, field_item, &args[1]);
      const bool cvt_arg2= convert_const_to_int(thd, field_item, &args[2]);
      if (cvt_arg1 && cvt_arg2)
      {
        // Works for all types
        m_comparator.set_handler(&type_handler_longlong);
      }
    }
  }
  return FALSE;
}


int cmp_longlong(void *cmp_arg,
                 in_longlong::packed_longlong *a,
                 in_longlong::packed_longlong *b)
{
  if (a->unsigned_flag != b->unsigned_flag)
  {
    /*
      One of the args is unsigned and is too big to fit into the
      positive signed range. Report no match.
    */
    if ((a->unsigned_flag && ((ulonglong) a->val) > (ulonglong) LONGLONG_MAX)
        ||
        (b->unsigned_flag && ((ulonglong) b->val) > (ulonglong) LONGLONG_MAX))
      return a->unsigned_flag ? 1 : -1;
    /*
      Although the signedness differs both args can fit into the signed
      positive range. Make them signed and compare as usual.
    */
    return cmp_longs(a->val, b->val);
  }
  if (a->unsigned_flag)
    return cmp_ulongs((ulonglong) a->val, (ulonglong) b->val);
  return cmp_longs(a->val, b->val);
}


my_decimal *Item_func_case::decimal_op(my_decimal *decimal_value)
{
  DBUG_ASSERT(fixed == 1);
  Item *item= find_item();
  my_decimal *res;

  if (!item)
  {
    null_value=1;
    return 0;
  }

  res= item->val_decimal(decimal_value);
  null_value= item->null_value;
  return res;
}


in_decimal::in_decimal(THD *thd, uint elements)
  :in_vector(thd, elements, sizeof(my_decimal), (qsort2_cmp) cmp_decimal, 0)
{}


in_row::in_row(THD *thd, uint elements, Item * item)
{
  base= (char*) new (thd->mem_root) cmp_item_row[count= elements];
  size= sizeof(cmp_item_row);
  compare= (qsort2_cmp) cmp_row;
  /*
    We need to reset these as otherwise we will call sort() with
    uninitialized (even if not used) elements
  */
  used_count= elements;
  collation= 0;
}


  Item_timestamp_literal(THD *thd)
   :Item_literal(thd)
  { }


Item_cond::fix_fields(THD *thd, Item **ref)
{
  DBUG_ASSERT(fixed == 0);
  List_iterator<Item> li(list);
  Item *item;
  uchar buff[sizeof(char*)];			// Max local vars in function
  bool is_and_cond= functype() == Item_func::COND_AND_FUNC;
  not_null_tables_cache= 0;
  used_tables_and_const_cache_init();

  /*
    and_table_cache is the value that Item_cond_or() returns for
    not_null_tables()
  */
  and_tables_cache= ~(table_map) 0;

  if (check_stack_overrun(thd, STACK_MIN_SIZE, buff))
    return TRUE;				// Fatal error flag is set!
  /*
    The following optimization reduces the depth of an AND-OR tree.
    E.g. a WHERE clause like
      F1 AND (F2 AND (F2 AND F4))
    is parsed into a tree with the same nested structure as defined
    by braces. This optimization will transform such tree into
      AND (F1, F2, F3, F4).
    Trees of OR items are flattened as well:
      ((F1 OR F2) OR (F3 OR F4))   =>   OR (F1, F2, F3, F4)
    Items for removed AND/OR levels will dangle until the death of the
    entire statement.
    The optimization is currently prepared statements and stored procedures
    friendly as it doesn't allocate any memory and its effects are durable
    (i.e. do not depend on PS/SP arguments).
  */
  while ((item=li++))
  {
    while (item->type() == Item::COND_ITEM &&
	   ((Item_cond*) item)->functype() == functype() &&
           !((Item_cond*) item)->list.is_empty())
    {						// Identical function
      li.replace(((Item_cond*) item)->list);
      ((Item_cond*) item)->list.empty();
      item= *li.ref();				// new current item
    }
    if (abort_on_null)
      item->top_level_item();

    /*
      replace degraded condition:
        was:    <field>
        become: <field> = 1
    */
    Item::Type type= item->type();
    if (type == Item::FIELD_ITEM || type == Item::REF_ITEM)
    {
      Query_arena backup, *arena;
      Item *new_item;
      arena= thd->activate_stmt_arena_if_needed(&backup);
      if ((new_item= new (thd->mem_root) Item_func_ne(thd, item, new (thd->mem_root) Item_int(thd, 0, 1))))
        li.replace(item= new_item);
      if (arena)
        thd->restore_active_arena(arena, &backup);
    }

    if (item->fix_fields_if_needed_for_bool(thd, li.ref()))
      return TRUE; /* purecov: inspected */
    item= *li.ref(); // item can be substituted in fix_fields
    used_tables_cache|=     item->used_tables();
    if (item->const_item() && !item->with_param &&
        !item->is_expensive() && !cond_has_datetime_is_null(item))
    {
      if (item->eval_const_cond() == is_and_cond && top_level())
      {
        /*
          a. This is "... AND true_cond AND ..."
          In this case, true_cond  has no effect on cond_and->not_null_tables()
          b. This is "... OR false_cond/null cond OR ..."
          In this case, false_cond has no effect on cond_or->not_null_tables()
        */
      }
      else
      {
        /*
          a. This is "... AND false_cond/null_cond AND ..."
          The whole condition is FALSE/UNKNOWN.
          b. This is  "... OR const_cond OR ..."
          In this case, cond_or->not_null_tables()=0, because the condition
          const_cond might evaluate to true (regardless of whether some tables
          were NULL-complemented).
        */
        not_null_tables_cache= (table_map) 0;
        and_tables_cache= (table_map) 0;
      }
      if (thd->is_error())
        return TRUE;
    }
    else
    {
      table_map tmp_table_map= item->not_null_tables();
      not_null_tables_cache|= tmp_table_map;
      and_tables_cache&= tmp_table_map;

      const_item_cache= FALSE;
    }

    join_with_sum_func(item);
    with_param|=       item->with_param;
    with_field|=       item->with_field;
    m_with_subquery|=  item->with_subquery();
    with_window_func|= item->with_window_func;
    maybe_null|=       item->maybe_null;
  }
  if (fix_length_and_dec())
    return TRUE;
  fixed= 1;
  return FALSE;
}


longlong val_int_min() const { return value; }


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

  List_iterator<Item> li(list);
  Item *item;
  while ((item= li++))
  {
    /*
      The same parameter value of arg_p must be passed
      to analyze any argument of the condition formula.
    */
    uchar *arg_v= *arg_p;
    Item *new_item= item->compile(thd, analyzer, &arg_v, transformer, arg_t);
    if (new_item && new_item != item)
      thd->change_item_tree(li.ref(), new_item);
  }
  return Item_func::transform(thd, transformer, arg_t);
}


  uint datetime_precision(THD *thd)
  {
    return const_item() ? type_handler()->Item_datetime_precision(thd, this) :
                          MY_MIN(decimals, TIME_SECOND_PART_DIGITS);
  }


  Item *field_transformer_for_having_pushdown(THD *thd, uchar *arg)
  { return (*ref)->field_transformer_for_having_pushdown(thd, arg); }


  bool can_return_const_value(Item_result type) const
  {
    return can_return_value() &&
           value.type_handler()->cmp_type() == type &&
           type_handler()->cmp_type() == type;
  }


inline bool TABLE::mark_virtual_column_with_deps(Field *field)
{
  bool res;
  DBUG_ASSERT(field->vcol_info);
  if (!(res= bitmap_fast_test_and_set(read_set, field->field_index)))
    mark_virtual_column_deps(field);
  return res;
}


const double *const_ptr_double() const { return &value; }


  virtual bool fix_fields(THD *, Item **)
  {
    /*
      This should not normally be called, because usually before
      fix_fields() we check is_fixed() to be false.
      But historically we allow fix_fields() to be called for Items
      who return basic_const_item()==true.
    */
    DBUG_ASSERT(is_fixed());
    DBUG_ASSERT(basic_const_item());
    return false;
  }


int cmp_item_decimal::cmp(Item *arg)
{
  VDec tmp(arg);
  return m_null_value || tmp.is_null() ? UNKNOWN : (tmp.cmp(&value) != 0);
}


inline const LEX_CSTRING *Item_splocal::my_name() const
{
  return &m_name;
}


String *val_str(String *to) { return cached_time.to_string(to, decimals); }


longlong Item_func_truth::val_int()
{
  return (val_bool() ? 1 : 0);
}


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


  longlong val_datetime_packed(THD *thd)
  {
    Datetime::Options_cmp opt(thd);
    return has_value() ? Datetime(thd, this, opt).to_packed() : 0;
  }


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


Item *in_longlong::create_item(THD *thd)
{
  /*
     We're created a signed INT, this may not be correct in
     general case (see BUG#19342).
  */
  return new (thd->mem_root) Item_int(thd, (longlong)0);
}


void Item_in_optimizer::fix_after_pullout(st_select_lex *new_parent,
                                          Item **ref, bool merge)
{
  DBUG_ASSERT(fixed);
  /* This will re-calculate attributes of our Item_in_subselect: */
  Item_bool_func::fix_after_pullout(new_parent, ref, merge);

  /* Then, re-calculate not_null_tables_cache: */
  eval_not_null_tables(NULL);
}


TYPELIB *get_typelib() const { return enum_set_typelib; }


bool Item_func_in::list_contains_null()
{
  Item **arg,**arg_end;
  for (arg= args + 1, arg_end= args+arg_count; arg != arg_end ; arg++)
  {
    if ((*arg)->null_inside())
      return 1;
  }
  return 0;
}


uchar *in_timestamp::get_value(Item *item)
{
  Timestamp_or_zero_datetime_native_null native(current_thd, item, true);
  if (native.is_null())
    return 0;
  tmp= Timestamp_or_zero_datetime(native);
  return (uchar*) &tmp;
}


uint cols() const { return this_item()->cols(); }


  virtual bool get_date_result(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
  { return get_date(thd, ltime,fuzzydate); }


bool Arg_comparator::set_cmp_func_row()
{
  func= is_owner_equal_func() ? &Arg_comparator::compare_e_row :
                                &Arg_comparator::compare_row;
  return set_cmp_func_for_row_arguments();
}


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


  bool fix_fields_if_needed_for_scalar(THD *thd, Item **ref)
  {
    return fix_fields_if_needed(thd, ref) || check_cols(1);
  }


void cmp_item_row::store_value_by_template(THD *thd, cmp_item *t, Item *item)
{
  cmp_item_row *tmpl= (cmp_item_row*) t;
  if (tmpl->n != item->cols())
  {
    my_error(ER_OPERAND_COLUMNS, MYF(0), tmpl->n);
    return;
  }
  n= tmpl->n;
  if ((comparators= (cmp_item **) thd->alloc(sizeof(cmp_item *)*n)))
  {
    item->bring_value();
    item->null_value= 0;
    for (uint i=0; i < n; i++)
    {
      if (!(comparators[i]= tmpl->comparators[i]->make_same()))
	break;					// new failed
      comparators[i]->store_value_by_template(thd, tmpl->comparators[i],
					      item->element_index(i));
      item->null_value|= item->element_index(i)->null_value;
    }
  }
}


Item *Item_func_le::negated_item(THD *thd) /* a <= b  ->  a > b */
{
  return new (thd->mem_root) Item_func_gt(thd, args[0], args[1]);
}


  const Type_handler *real_type_handler() const
  {
    if (field->is_created_from_null_item)
      return &type_handler_null;
    return field->type_handler();
  }


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


  bool fix_fields(THD *thd, Item **ref)
  {
    DBUG_ASSERT(!fixed);
    fixed= true;
    return false;
  }


cmp_item* cmp_item_decimal::make_same()
{
  return new cmp_item_decimal();
}


void Item_equal::update_const(THD *thd)
{
  List_iterator<Item> it(equal_items);
  if (with_const)
    it++;
  Item *item;
  while ((item= it++))
  {
    if (item->const_item() && !item->is_expensive() &&
        /*
          Don't propagate constant status of outer-joined column.
          Such a constant status here is a result of:
            a) empty outer-joined table: in this case such a column has a
               value of NULL; but at the same time other arguments of
               Item_equal don't have to be NULLs and the value of the whole
               multiple equivalence expression doesn't have to be NULL or FALSE
               because of the outer join nature;
          or
            b) outer-joined table contains only 1 row: the result of
               this column is equal to a row field value *or* NULL.
          Both values are inacceptable as Item_equal constants.
        */
        !item->is_outer_field())
    {
      if (item == equal_items.head())
        with_const= TRUE;
      else
      {
        it.remove();
        add_const(thd, item);
      }
    }
  }
}


Item_cond::Item_cond(THD *thd, Item *i1, Item *i2):
  Item_bool_func(thd), abort_on_null(0)
{
  list.push_back(i1, thd->mem_root);
  list.push_back(i2, thd->mem_root);
}


inline void TABLE::use_all_stored_columns()
{
  bitmap_set_all(read_set);
  if (Field **vf= vfield)
    for (; *vf; vf++)
      bitmap_clear_bit(read_set, (*vf)->field_index);
}


  String *val_str(String *to)
  {
    return has_value() ? Date(this).to_string(to) : NULL;
  }


Item_func_in::eval_not_null_tables(void *opt_arg)
{
  Item **arg, **arg_end;

  if (Item_func_opt_neg::eval_not_null_tables(NULL))
    return 1;

  /* not_null_tables_cache == union(T1(e),union(T1(ei))) */
  if (pred_level && negated)
    return 0;

  /* not_null_tables_cache = union(T1(e),intersection(T1(ei))) */
  not_null_tables_cache= ~(table_map) 0;
  for (arg= args + 1, arg_end= args + arg_count; arg != arg_end; arg++)
    not_null_tables_cache&= (*arg)->not_null_tables();
  not_null_tables_cache|= (*args)->not_null_tables();
  return 0;
}


longlong Item_func_dyncol_exists::val_int()
{
  char buff[STRING_BUFFER_USUAL_SIZE], nmstrbuf[11];
  String tmp(buff, sizeof(buff), &my_charset_bin),
         nmbuf(nmstrbuf, sizeof(nmstrbuf), system_charset_info);
  DYNAMIC_COLUMN col;
  String *str;
  LEX_STRING buf, *name= NULL;
  ulonglong num= 0;
  enum enum_dyncol_func_result rc;

  if (args[1]->result_type() == INT_RESULT)
    num= args[1]->val_int();
  else
  {
    String *nm= args[1]->val_str(&nmbuf);
    if (!nm || args[1]->null_value)
    {
      null_value= 1;
      return 1;
    }
    if (my_charset_same(nm->charset(), DYNCOL_UTF))
    {
      buf.str= (char *) nm->ptr();
      buf.length= nm->length();
    }
    else
    {
      uint strlen= nm->length() * DYNCOL_UTF->mbmaxlen + 1;
      uint dummy_errors;
      buf.str= (char *) current_thd->alloc(strlen);
      if (buf.str)
      {
        buf.length=
          copy_and_convert(buf.str, strlen, DYNCOL_UTF,
                           nm->ptr(), nm->length(), nm->charset(),
                           &dummy_errors);
      }
      else
        buf.length= 0;
    }
    name= &buf;
  }
  str= args[0]->val_str(&tmp);
  if (args[0]->null_value || args[1]->null_value || num > UINT_MAX16)
    goto null;
  col.length= str->length();
  /* We do not change the string, so could do this trick */
  col.str= (char *)str->ptr();
  rc= ((name == NULL) ?
       mariadb_dyncol_exists_num(&col, (uint) num) :
       mariadb_dyncol_exists_named(&col, name));
  if (rc < 0)
  {
    dynamic_column_error_message(rc);
    goto null;
  }
  null_value= FALSE;
  return rc == ER_DYNCOL_YES;

null:
  null_value= TRUE;
  return 0;
}


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


int cmp_item_time::cmp(Item *arg)
{
  const bool rc= value != arg->val_time_packed(current_thd);
  return (m_null_value || arg->null_value) ? UNKNOWN : rc;
}


  bool fix_fields_if_needed(THD *thd, Item **ref)
  {
    return is_fixed() ? false : fix_fields(thd, ref);
  }


  my_decimal *val_decimal(my_decimal *to)
  {
    DBUG_ASSERT(sane());
    return null_value ? NULL :
           m_value.to_datetime(current_thd).to_decimal(to);
  }


  double val_real()
  {
    DBUG_ASSERT(sane());
    return null_value ? 0e0 :
           m_value.to_datetime(current_thd).to_double();
  }


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


Item *Item_cond_and::neg_transformer(THD *thd)	/* NOT(a AND b AND ...)  -> */
					/* NOT a OR NOT b OR ... */
{
  neg_arguments(thd);
  Item *item= new (thd->mem_root) Item_cond_or(thd, list);
  return item;
}


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


Item *in_decimal::create_item(THD *thd)
{
  return new (thd->mem_root) Item_decimal(thd, 0, FALSE);
}


Item_cond::eval_not_null_tables(void *opt_arg)
{
  Item *item;
  bool is_and_cond= functype() == Item_func::COND_AND_FUNC;
  List_iterator<Item> li(list);
  not_null_tables_cache= (table_map) 0;
  and_tables_cache= ~(table_map) 0;
  while ((item=li++))
  {
    table_map tmp_table_map;
    if (item->const_item() && !item->with_param &&
        !item->is_expensive() && !cond_has_datetime_is_null(item))
    {
      if (item->eval_const_cond() == is_and_cond && top_level())
      {
        /*
          a. This is "... AND true_cond AND ..."
          In this case, true_cond  has no effect on cond_and->not_null_tables()
          b. This is "... OR false_cond/null cond OR ..."
          In this case, false_cond has no effect on cond_or->not_null_tables()
        */
      }
      else
      {
        /*
          a. This is "... AND false_cond/null_cond AND ..."
          The whole condition is FALSE/UNKNOWN.
          b. This is  "... OR const_cond OR ..."
          In this case, cond_or->not_null_tables()=0, because the condition
          const_cond might evaluate to true (regardless of whether some tables
          were NULL-complemented).
        */
        not_null_tables_cache= (table_map) 0;
        and_tables_cache= (table_map) 0;
      }
    }
    else
    {
      tmp_table_map= item->not_null_tables();
      not_null_tables_cache|= tmp_table_map;
      and_tables_cache&= tmp_table_map;
    }
  }
  return 0;
}


  my_decimal *val_decimal(my_decimal *to)
  {
    return update_null() ? 0 : cached_time.to_decimal(to);
  }


  String *val_str(String *to)
  {
    return has_value() ? Time(this).to_string(to, decimals) : NULL;
  }


bool Item_in_optimizer::is_expensive()
{
  DBUG_ASSERT(fixed);
  return args[0]->is_expensive() || args[1]->is_expensive();
}


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


bool make_copy_field() const { return m_make_copy_field; }


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


void Item_func_between::print(String *str, enum_query_type query_type)
{
  args[0]->print_parenthesised(str, query_type, higher_precedence());
  if (negated)
    str->append(STRING_WITH_LEN(" not"));
  str->append(STRING_WITH_LEN(" between "));
  args[1]->print_parenthesised(str, query_type, precedence());
  str->append(STRING_WITH_LEN(" and "));
  args[2]->print_parenthesised(str, query_type, precedence());
}


  String *val_str(String *to)
  {
    return has_value() ? Datetime(this).to_string(to, decimals) : NULL;
  }


  Item_cache_timestamp(THD *thd)
   :Item_cache(thd, &type_handler_timestamp2) { }


bool Item_cond::excl_dep_on_grouping_fields(st_select_lex *sel)
{
  if (has_rand_bit())
    return false;
  List_iterator_fast<Item> li(list);
  Item *item;
  while ((item= li++))
  {
    if (!item->excl_dep_on_grouping_fields(sel))
      return false;
  }
  return true;
}


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


void in_timestamp::value_to_item(uint pos, Item *item)
{
  const Timestamp_or_zero_datetime &buff= (((Timestamp_or_zero_datetime*) base)[pos]);
  static_cast<Item_timestamp_literal*>(item)->set_value(buff);
}


Item *in_temporal::create_item(THD *thd)
{
  return new (thd->mem_root) Item_datetime(thd);
}


  my_decimal *val_decimal(my_decimal *to)
  {
    return m_value.to_datetime(current_thd).to_decimal(to);
  }


  Item_copy(THD *thd, Item *i): Item(thd)
  {
    DBUG_ASSERT(i->is_fixed());
    item= i;
    null_value=maybe_null=item->maybe_null;
    Type_std_attributes::set(item);
    name= item->name;
    set_handler(item->type_handler());
  }


bool Item_func_ifnull::date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
  DBUG_ASSERT(fixed == 1);
  for (uint i= 0; i < 2; i++)
  {
    Datetime_truncation_not_needed dt(thd, args[i],
                                      fuzzydate & ~TIME_FUZZY_DATES);
    if (!(dt.copy_to_mysql_time(ltime, mysql_timestamp_type())))
      return (null_value= false);
  }
  return (null_value= true);
}


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

  List_iterator<Item> li(list);
  Item *item;
  while ((item= li++))
  {
    Item *new_item= item->transform(thd, transformer, arg);
    if (!new_item)
      return 0;

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


in_string::~in_string()
{
  if (base)
  {
    // base was allocated on THD::mem_root => following is OK
    for (uint i=0 ; i < count ; i++)
      ((String*) base)[i].free();
  }
}


Item_func_regexp_instr::fix_length_and_dec()
{
  if (agg_arg_charsets_for_comparison(cmp_collation, args, 2))
    return TRUE;

  re.init(cmp_collation.collation, 0);
  re.fix_owner(this, args[0], args[1]);
  max_length= MY_INT32_NUM_DECIMAL_DIGITS; // See also Item_func_locate
  return FALSE;
}


  Type_geometry_attributes()
   :m_geometry_type(m_geometry_type_unknown)
  { }


Item *Item_func_xor::neg_transformer(THD *thd)
{
  Item *neg_operand;
  Item_func_xor *new_item;
  if ((neg_operand= args[0]->neg_transformer(thd)))
    // args[0] has neg_tranformer
    new_item= new(thd->mem_root) Item_func_xor(thd, neg_operand, args[1]);
  else if ((neg_operand= args[1]->neg_transformer(thd)))
    // args[1] has neg_tranformer
    new_item= new(thd->mem_root) Item_func_xor(thd, args[0], neg_operand);
  else
  {
    neg_operand= new(thd->mem_root) Item_func_not(thd, args[0]);
    new_item= new(thd->mem_root) Item_func_xor(thd, neg_operand, args[1]);
  }
  return new_item;
}


virtual bool is_fixed() const { return true; }


int Arg_comparator::compare_datetime()
{
  THD *thd= current_thd;
  longlong val1= (*a)->val_datetime_packed(thd);
  if (!(*a)->null_value)
  {
    longlong val2= (*b)->val_datetime_packed(thd);
    if (!(*b)->null_value)
      return compare_not_null_values(val1, val2);
  }
  if (set_null)
    owner->null_value= true;
  return -1;
}


longlong Item_func_between::val_int_cmp_int()
{
  Longlong_hybrid value= args[0]->to_longlong_hybrid();
  if ((null_value= args[0]->null_value))
    return 0;					/* purecov: inspected */
  Longlong_hybrid a= args[1]->to_longlong_hybrid();
  Longlong_hybrid b= args[2]->to_longlong_hybrid();
  if (!args[1]->null_value && !args[2]->null_value)
    return (longlong) ((value.cmp(a) >= 0 && value.cmp(b) <= 0) != negated);
  if (args[1]->null_value && args[2]->null_value)
    null_value= true;
  else if (args[1]->null_value)
    null_value= value.cmp(b) <= 0;              // not null if false range.
  else
    null_value= value.cmp(a) >= 0;
  return (longlong) (!null_value && negated);
}


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


  Field *create_field_for_create_select(TABLE *table)
  { return tmp_table_field_from_field_type(table); }


  void fix_charset_and_length(CHARSET_INFO *cs,
                              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(cs, dv, metadata.repertoire());
    fix_char_length(metadata.char_length());
    decimals= NOT_FIXED_DEC;
  }


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


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


bool Item_func_in::value_list_convert_const_to_int(THD *thd)
{
  if (args[0]->real_item()->type() == FIELD_ITEM &&
      !thd->lex->is_view_context_analysis())
  {
    Item_field *field_item= (Item_field*) (args[0]->real_item());
    if (field_item->field_type() == MYSQL_TYPE_LONGLONG ||
        field_item->field_type() == MYSQL_TYPE_YEAR)
    {
      bool all_converted= true;
      Item **arg, **arg_end;
      for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++)
      {
          /*
            Explicit NULLs should not affect data cmp_type resolution:
            - we ignore NULLs when calling collect_cmp_type()
            - we ignore NULLs here
            So this expression:
              year_column IN (DATE'2001-01-01', NULL)
            switches from TIME_RESULT to INT_RESULT.
          */
          if (arg[0]->type() != Item::NULL_ITEM &&
              !convert_const_to_int(thd, field_item, &arg[0]))
           all_converted= false;
      }
      if (all_converted)
        m_comparator.set_handler(&type_handler_longlong);
    }
  }
  return thd->is_fatal_error; // Catch errrors in convert_const_to_int
}


  Item_type_holder(THD *thd, Item *item)
   :Item(thd, item),
    Type_handler_hybrid_field_type(item->real_type_handler()),
    enum_set_typelib(0)
  {
    DBUG_ASSERT(item->is_fixed());
    maybe_null= item->maybe_null;
  }


bool is_string() const { return m_type == DYN_COL_STRING; }


  Item_int(THD *thd, const char *str_arg,longlong i,size_t length):
    Item_num(thd), value(i)
    {
      max_length=(uint32)length;
      name.str= str_arg; name.length= safe_strlen(name.str);
    }


String *Item_func_coalesce::str_op(String *str)
{
  DBUG_ASSERT(fixed == 1);
  null_value=0;
  for (uint i=0 ; i < arg_count ; i++)
  {
    String *res;
    if ((res=args[i]->val_str(str)))
      return res;
  }
  null_value=1;
  return 0;
}


  void set_item_result_field(Item_result_field *item)
  { m_item_result_field= item; }


bool Predicant_to_list_comparator::add_value_skip_null(const char *funcname,
                                                       Item_args *args,
                                                       uint value_index,
                                                       bool *nulls_found)
{
  /*
    Skip explicit NULL constant items.
    Using real_item() to correctly detect references to explicit NULLs
    in HAVING clause, e.g. in this example "b" is skipped:
      SELECT a,NULL AS b FROM t1 GROUP BY a HAVING 'A' IN (b,'A');
  */
  if (args->arguments()[value_index]->real_item()->type() == Item::NULL_ITEM)
  {
    *nulls_found= true;
    return false;
  }
  return add_value(funcname, args, value_index);
}


void Item_func_in::fix_in_vector()
{
  DBUG_ASSERT(array);
  uint j=0;
  for (uint i=1 ; i < arg_count ; i++)
  {
    array->set(j,args[i]);
    if (!args[i]->null_value)
      j++; // include this cell in the array.
    else
    {
      /*
        We don't put NULL values in array, to avoid erronous matches in
        bisection.
      */
      have_null= 1;
    }
  }
  if ((array->used_count= j))
    array->sort();
}


  longlong val_int()
  {
    return to_datetime(current_thd).to_longlong();
  }


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


bool Regexp_processor_pcre::exec(const char *str, size_t length, size_t offset)
{
  m_pcre_exec_rc= pcre_exec_with_warn(m_pcre, &m_pcre_extra, str, (int)length, (int)offset, 0,
                                      m_SubStrVec, array_elements(m_SubStrVec));
  return false;
}


bool with_sum_func() const { return m_with_sum_func; }


  my_decimal *val_decimal(my_decimal *decimal_value)
  {
    DBUG_ASSERT(0); // never should be called
    null_value= true;
    return 0;
  }


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


  virtual const Type_handler *real_type_handler() const
  {
    return type_handler();
  }


cmp_item* cmp_item_int::make_same()
{
  return new cmp_item_int();
}


longlong Item_func_ge::val_int()
{
  DBUG_ASSERT(fixed == 1);
  int value= cmp.compare();
  return value >= 0 ? 1 : 0;
}


void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item)
{
  List_iterator_fast<Item> li(item->list);
  while (Item *it= li++)
    list.push_back(it->copy_andor_structure(thd), thd->mem_root);
}


int Arg_comparator::compare_int_signed()
{
  longlong val1= (*a)->val_int();
  if (!(*a)->null_value)
  {
    longlong val2= (*b)->val_int();
    if (!(*b)->null_value)
      return compare_not_null_values(val1, val2);
  }
  if (set_null)
    owner->null_value= 1;
  return -1;
}


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


Item_func_regex::fix_length_and_dec()
{
  if (Item_bool_func::fix_length_and_dec() ||
      agg_arg_charsets_for_comparison(cmp_collation, args, 2))
    return TRUE;

  re.init(cmp_collation.collation, 0);
  re.fix_owner(this, args[0], args[1]);
  return FALSE;
}


  Field::geometry_type get_geometry_type() const
  {
    return m_geometry_type == m_geometry_type_unknown ?
           Field::GEOM_GEOMETRY :
           (Field::geometry_type) m_geometry_type;
  }


bool is_decimal() const { return m_type == DYN_COL_DECIMAL; }


in_row::~in_row()
{
  if (base)
    delete [] (cmp_item_row*) base;
}


bool Item_func_coalesce::native_op(THD *thd, Native *to)
{
  DBUG_ASSERT(fixed == 1);
  for (uint i= 0; i < arg_count; i++)
  {
    if (!val_native_with_conversion_from_item(thd, args[i], to, type_handler()))
      return false;
  }
  return (null_value= true);
}


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


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


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


  String* val_str(String *to)
  {
    return to_datetime(current_thd).to_string(to, decimals);
  }


bool Item_func_ifnull::time_op(THD *thd, MYSQL_TIME *ltime)
{
  DBUG_ASSERT(fixed == 1);
  for (uint i= 0; i < 2; i++)
  {
    if (!Time(thd, args[i]).copy_to_mysql_time(ltime))
      return (null_value= false);
  }
  return (null_value= true);
}


bool Item_func_case_simple::aggregate_switch_and_when_arguments(THD *thd,
                                                                bool nulls_eq)
{
  uint ncases= when_count();
  m_found_types= 0;
  if (prepare_predicant_and_values(thd, &m_found_types, nulls_eq))
  {
    /*
      If Predicant_to_list_comparator() fails to prepare components,
      it must put an error into the diagnostics area. This is needed
      to make fix_fields() catches such errors.
    */
    DBUG_ASSERT(thd->is_error());
    return true;
  }

  if (!(m_found_types= collect_cmp_types(args, ncases + 1)))
    return true;

  if (m_found_types & (1U << STRING_RESULT))
  {
    /*
      If we'll do string comparison, we also need to aggregate
      character set and collation for first/WHEN items and
      install converters for some of them to cmp_collation when necessary.
      This is done because cmp_item compatators cannot compare
      strings in two different character sets.
      Some examples when we install converters:

      1. Converter installed for the first expression:

         CASE         latin1_item              WHEN utf16_item THEN ... END

      is replaced to:

         CASE CONVERT(latin1_item USING utf16) WHEN utf16_item THEN ... END

      2. Converter installed for the left WHEN item:

        CASE utf16_item WHEN         latin1_item              THEN ... END

      is replaced to:

         CASE utf16_item WHEN CONVERT(latin1_item USING utf16) THEN ... END
    */
    if (agg_arg_charsets_for_comparison(cmp_collation, args, ncases + 1))
      return true;
  }

  if (make_unique_cmp_items(thd, cmp_collation.collation))
    return true;

  return false;
}


longlong Item_func_nop_all::val_int()
{
  DBUG_ASSERT(fixed == 1);
  longlong value= args[0]->val_int();

  /*
    return FALSE if there was records in underlying select in max/min
    optimization (SAME/ANY subquery)
  */
  if (empty_underlying_subquery())
    return 0;

  null_value= args[0]->null_value;
  return (null_value || value == 0) ? 0 : 1;
}


  uint time_precision(THD *thd)
  {
    return const_item() ? type_handler()->Item_time_precision(thd, this) :
                          MY_MIN(decimals, TIME_SECOND_PART_DIGITS);
  }


  void cleanup()
  {
    clear();
    Item::cleanup();
  }


Item_bool_rowready_func2* Eq_creator::create_swap(THD *thd, Item *a, Item *b) const
{
  return new(thd->mem_root) Item_func_eq(thd, b, a);
}


Item *Item_cond_or::neg_transformer(THD *thd)	/* NOT(a OR b OR ...)  -> */
					/* NOT a AND NOT b AND ... */
{
  neg_arguments(thd);
  Item *item= new (thd->mem_root) Item_cond_and(thd, list);
  return item;
}


void in_timestamp::set(uint pos, Item *item)
{
  Timestamp_or_zero_datetime *buff= &((Timestamp_or_zero_datetime *) base)[pos];
  Timestamp_or_zero_datetime_native_null native(current_thd, item, true);
  if (native.is_null())
    *buff= Timestamp_or_zero_datetime();
  else
    *buff= Timestamp_or_zero_datetime(native);
}


longlong Item_func_regex::val_int()
{
  DBUG_ASSERT(fixed == 1);
  if ((null_value= re.recompile(args[1])))
    return 0;

  if ((null_value= re.exec(args[0], 0, 0)))
    return 0;

  return re.match();
}


Item_bool_rowready_func2* Gt_creator::create(THD *thd, Item *a, Item *b) const
{
  return new(thd->mem_root) Item_func_gt(thd, a, b);
}


  longlong val_int()
  {
    return can_return_value() ? value.val_int(this) : 0;
  }


const my_decimal *const_ptr_my_decimal() const { return &decimal_value; }


  virtual bool set_extraction_flag_processor(void *arg)
  {
    set_extraction_flag(*(int*)arg);
    return 0;
  }


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


virtual const longlong *const_ptr_longlong() const { return NULL; }


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


Item *Item_cond_or::copy_andor_structure(THD *thd)
{
  Item_cond_or *item;
  if ((item= new (thd->mem_root) Item_cond_or(thd, this)))
    item->copy_andor_arguments(thd, this);
  return item;
}


  bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
  {
    cached_time.copy_to_mysql_time(ltime);
    return (null_value= false);
  }


  Item_cache* get_cache(THD *thd) const
  {
    return type_handler()->Item_get_cache(thd, this);
  }


  Item_direct_ref(THD *thd, TABLE_LIST *view_arg, Item **item,
                  const LEX_CSTRING *field_name_arg,
                  bool alias_name_used_arg= FALSE):
    Item_ref(thd, view_arg, item, field_name_arg,
             alias_name_used_arg)
  {}


bool Item_bool_func2::count_sargable_conds(void *arg)
{
  ((SELECT_LEX*) arg)->cond_count++;
  return 0;
}


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


uchar *in_decimal::get_value(Item *item)
{
  my_decimal *result= item->val_decimal(&val);
  if (item->null_value)
    return 0;
  return (uchar *)result;
}


Item *Item_func_eq::negated_item(THD *thd) /* a = b  ->  a != b */
{
  return new (thd->mem_root) Item_func_ne(thd, args[0], args[1]);
}


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


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


void cmp_item_decimal::store_value(Item *item)
{
  my_decimal *val= item->val_decimal(&value);
  /* val may be zero if item is nnull */
  if (val && val != &value)
    my_decimal2decimal(val, &value);
  m_null_value= item->null_value;
}


  bool fix_fields_if_needed_for_bool(THD *thd, Item **ref)
  {
    return fix_fields_if_needed_for_scalar(thd, ref);
  }


void reset_with_sum_func() { m_with_sum_func= false; }


virtual const double *const_ptr_double() const { return NULL; }


int Arg_comparator::compare_string()
{
  String *res1,*res2;
  if ((res1= (*a)->val_str(&value1)))
  {
    if ((res2= (*b)->val_str(&value2)))
    {
      if (set_null)
        owner->null_value= 0;
      return sortcmp(res1, res2, compare_collation());
    }
  }
  if (set_null)
    owner->null_value= 1;
  return -1;
}


  bool val_native_with_conversion(THD *thd, Native *to, const Type_handler *th)
  {
    return th->Item_val_native_with_conversion(thd, this, to);
  }


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


int Arg_comparator::compare_json_str()
{
  return compare_json_str_basic(*a, *b);
}


  virtual Item *make_odbc_literal(THD *thd, const LEX_CSTRING *typestr)
  {
    return this;
  }


  Item_int(THD *thd, int32 i,size_t length= MY_INT32_NUM_DECIMAL_DIGITS):
    Item_num(thd), value((longlong) i)
    { max_length=(uint32)length; }


  Item *remove_item_direct_ref()
  { return (*ref)->remove_item_direct_ref(); }


  bool val_native_from_field(Field *field, Native *to)
  {
    if ((null_value= field->is_null()))
      return true;
    return (null_value= field->val_native(to));
  }


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


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


void set_field(Field *field) { m_field= field; }


void Item_in_optimizer::keep_top_level_cache()
{
  cache->keep_array();
  save_cache= 1;
}


int Regexp_processor_pcre::pcre_exec_with_warn(const pcre *code,
                                               const pcre_extra *extra,
                                               const char *subject,
                                               int length, int startoffset,
                                               int options, int *ovector,
                                               int ovecsize)
{
  int rc= pcre_exec(code, extra, subject, length,
                    startoffset, options, ovector, ovecsize);
  DBUG_EXECUTE_IF("pcre_exec_error_123", rc= -123;);
  if (unlikely(rc < PCRE_ERROR_NOMATCH))
    pcre_exec_warn(rc);
  return rc;
}


  bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
  { return get_date_from_int(thd, ltime, fuzzydate); }


bool Item_func_coalesce::date_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
  DBUG_ASSERT(fixed == 1);
  for (uint i= 0; i < arg_count; i++)
  {
    Datetime_truncation_not_needed dt(thd, args[i],
                                      fuzzydate & ~TIME_FUZZY_DATES);
    if (!dt.copy_to_mysql_time(ltime, mysql_timestamp_type()))
      return (null_value= false);
  }
  return (null_value= true);
}


cmp_item_row::~cmp_item_row()
{
  DBUG_ENTER("~cmp_item_row");
  DBUG_PRINT("enter",("this: %p", this));
  if (comparators)
  {
    for (uint i= 0; i < n; i++)
    {
      if (comparators[i])
	delete comparators[i];
    }
  }
  DBUG_VOID_RETURN;
}


  Item_cache_time(THD *thd)
   :Item_cache_temporal(thd, &type_handler_time2) { }


Item_equal::Item_equal(THD *thd, Item_equal *item_equal):
  Item_bool_func(thd), eval_item(0), cond_false(0), cond_true(0),
  context_field(NULL), link_equal_fields(FALSE),
  m_compare_handler(item_equal->m_compare_handler),
  m_compare_collation(item_equal->m_compare_collation)
{
  const_item_cache= 0;
  List_iterator_fast<Item> li(item_equal->equal_items);
  Item *item;
  while ((item= li++))
  {
    equal_items.push_back(item, thd->mem_root);
  }
  with_const= item_equal->with_const;
  cond_false= item_equal->cond_false;
  upper_levels= item_equal->upper_levels;
}


  const Type_handler *string_type_handler() const
  {
    return Type_handler::string_type_handler(max_length);
  }


Item_bool_rowready_func2* Le_creator::create_swap(THD *thd, Item *a, Item *b) const
{
  return new(thd->mem_root) Item_func_ge(thd, b, a);
}


int Arg_comparator::compare_e_time()
{
  THD *thd= current_thd;
  longlong val1= (*a)->val_time_packed(thd);
  longlong val2= (*b)->val_time_packed(thd);
  if ((*a)->null_value || (*b)->null_value)
    return MY_TEST((*a)->null_value && (*b)->null_value);
  return MY_TEST(val1 == val2);
}


  longlong val_datetime_packed(THD *thd)
  {
    return update_null() ? 0 : cached_time.valid_datetime_to_packed();
  }


  Item_args(THD *thd, Item *a, Item *b, Item *c, Item *d, Item* e)
  {
    arg_count= 5;
    if (likely((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;
    }
  }


Type_handler_hybrid_field_type::aggregate_for_comparison(const char *funcname,
                                                         Item **items,
                                                         uint nitems,
                                                         bool int_uint_as_dec)
{
  uint unsigned_count= items[0]->unsigned_flag;
  /*
    Convert sub-type to super-type (e.g. DATE to DATETIME, INT to BIGINT, etc).
    Otherwise Predicant_to_list_comparator will treat sub-types of the same
    super-type as different data types and won't be able to use bisection in
    many cases.
  */
  set_handler(items[0]->type_handler()->type_handler_for_comparison());
  for (uint i= 1 ; i < nitems ; i++)
  {
    unsigned_count+= items[i]->unsigned_flag;
    if (aggregate_for_comparison(items[i]->type_handler()->
                                 type_handler_for_comparison()))
    {
      /*
        For more precise error messages if aggregation failed on the first pair
        {items[0],items[1]}, use the name of items[0]->data_handler().
        Otherwise use the name of this->type_handler(), which is already a
        result of aggregation for items[0]..items[i-1].
      */
      my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
               i == 1 ? items[0]->type_handler()->name().ptr() :
                        type_handler()->name().ptr(),
               items[i]->type_handler()->name().ptr(),
               funcname);
      return true;
    }
    /*
      When aggregating types of two row expressions we have to check
      that they have the same cardinality and that each component
      of the first row expression has a compatible row signature with
      the signature of the corresponding component of the second row
      expression.
    */
    if (cmp_type() == ROW_RESULT && cmp_row_type(items[0], items[i]))
      return true;     // error found: invalid usage of rows
  }
  /**
    If all arguments are of INT type but have different unsigned_flag values,
    switch to DECIMAL_RESULT.
  */
  if (int_uint_as_dec &&
      cmp_type() == INT_RESULT &&
      unsigned_count != nitems && unsigned_count != 0)
    set_handler(&type_handler_newdecimal);
  return 0;
}


  TYPELIB *get_typelib() const
  {
    return ref ? (*ref)->get_typelib() : NULL;
  }


longlong Item_cond_and::val_int()
{
  DBUG_ASSERT(fixed == 1);
  List_iterator_fast<Item> li(list);
  Item *item;
  null_value= 0;
  while ((item=li++))
  {
    if (!item->val_bool())
    {
      if (abort_on_null || !(null_value= item->null_value))
	return 0;				// return FALSE
    }
  }
  return null_value ? 0 : 1;
}


virtual Item_param *get_item_param() { return 0; }


  Item_ref(THD *thd, Name_resolution_context *context_arg,
           const char *db_arg, const char *table_name_arg,
           const LEX_CSTRING *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) {}


  virtual longlong val_int_signed_typecast()
  {
    return cast_to_int_type_handler()->Item_val_int_signed_typecast(this);
  }


bool Item_in_optimizer::eval_not_null_tables(void *opt_arg)
{
  not_null_tables_cache= 0;
  if (is_top_level_item())
  {
    /*
      It is possible to determine NULL-rejectedness of the left arguments
      of IN only if it is a top-level predicate.
    */
    not_null_tables_cache= args[0]->not_null_tables();
  }
  return FALSE;
}


  void copy()
  {
    Timestamp_or_zero_datetime_native_null tmp(current_thd, item, false);
    null_value= tmp.is_null();
    m_value= tmp.is_null() ? Timestamp_or_zero_datetime() :
                             Timestamp_or_zero_datetime(tmp);
  }


bool Item_equal::fix_length_and_dec()
{
  Item *item= get_first(NO_PARTICULAR_TAB, NULL);
  const Type_handler *handler= item->type_handler();
  eval_item= handler->make_cmp_item(current_thd, item->collation.collation);
  return eval_item == NULL;
}


  bool update_null()
  {
    return maybe_null &&
           (null_value= cached_time.check_date_with_warn(current_thd));
  }


Item_param *get_item_param() { return this; }


Item *in_double::create_item(THD *thd)
{
  return new (thd->mem_root) Item_float(thd, 0.0, 0);
}


  bool send(Protocol *protocol, st_value *buffer)
  {
    return value_item->send(protocol, buffer);
  }


  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.str, arg, VCOL_FIELD_REF | VCOL_AUTO_INC);
    }
    return mark_unsupported_function(field_name.str, arg, VCOL_FIELD_REF);
  }


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


static int cmp_row_type(Item* item1, Item* item2)
{
  uint n= item1->cols();
  if (item2->check_cols(n))
    return 1;
  for (uint i=0; i<n; i++)
  {
    if (item2->element_index(i)->check_cols(item1->element_index(i)->cols()) ||
        (item1->element_index(i)->result_type() == ROW_RESULT &&
         cmp_row_type(item1->element_index(i), item2->element_index(i))))
      return 1;
  }
  return 0;
}


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


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


  void print(String *str, enum_query_type query_type)
  {
    str->append(STRING_WITH_LEN("ignore"));
  }


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


  bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred)
  { return (*ref)->excl_dep_on_in_subq_left_part(subq_pred); }


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


int Arg_comparator::compare_decimal()
{
  VDec val1(*a);
  if (!val1.is_null())
  {
    VDec val2(*b);
    if (!val2.is_null())
    {
      if (set_null)
        owner->null_value= 0;
      val1.round_self_if_needed((*a)->decimals, HALF_UP);
      val2.round_self_if_needed((*b)->decimals, HALF_UP);
      return val1.cmp(val2);
    }
  }
  if (set_null)
    owner->null_value= 1;
  return -1;
}


  virtual Item_basic_constant *make_string_literal_concat(THD *thd,
                                                          const LEX_CSTRING *)
  {
    DBUG_ASSERT(0);
    return this;
  }


static int cmp_timestamp(void *cmp_arg,
                         Timestamp_or_zero_datetime *a,
                         Timestamp_or_zero_datetime *b)
{
  return a->cmp(*b);
}


void Item_func_isnotnull::print(String *str, enum_query_type query_type)
{
  args[0]->print_parenthesised(str, query_type, precedence());
  str->append(STRING_WITH_LEN(" is not null"));
}


void cmp_item_timestamp::store_value(Item *item)
{
  item->val_native_with_conversion(current_thd, &m_native,
                                   &type_handler_timestamp2);
  m_null_value= item->null_value;
}


int cmp_item_datetime::cmp(Item *arg)
{
  const bool rc= value != arg->val_datetime_packed(current_thd);
  return (m_null_value || arg->null_value) ? UNKNOWN : rc;
}


void Regexp_processor_pcre::pcre_exec_warn(int rc) const
{
  char buf[64];
  const char *errmsg= NULL;
  THD *thd= current_thd;

  /*
    Make a descriptive message only for those pcre_exec() error codes
    that can actually happen in MariaDB.
  */
  switch (rc)
  {
  case PCRE_ERROR_NULL:
    errmsg= "pcre_exec: null argument passed";
    break;
  case PCRE_ERROR_BADOPTION:
    errmsg= "pcre_exec: bad option";
    break;
  case PCRE_ERROR_BADMAGIC:
    errmsg= "pcre_exec: bad magic - not a compiled regex";
    break;
  case PCRE_ERROR_UNKNOWN_OPCODE:
    errmsg= "pcre_exec: error in compiled regex";
    break;
  case PCRE_ERROR_NOMEMORY:
    errmsg= "pcre_exec: Out of memory";
    break;
  case PCRE_ERROR_NOSUBSTRING:
    errmsg= "pcre_exec: no substring";
    break;
  case PCRE_ERROR_MATCHLIMIT:
    errmsg= "pcre_exec: match limit exceeded";
    break;
  case PCRE_ERROR_CALLOUT:
    errmsg= "pcre_exec: callout error";
    break;
  case PCRE_ERROR_BADUTF8:
    errmsg= "pcre_exec: Invalid utf8 byte sequence in the subject string";
    break;
  case PCRE_ERROR_BADUTF8_OFFSET:
    errmsg= "pcre_exec: Started at invalid location within utf8 byte sequence";
    break;
  case PCRE_ERROR_PARTIAL:
    errmsg= "pcre_exec: partial match";
    break;
  case PCRE_ERROR_INTERNAL:
    errmsg= "pcre_exec: internal error";
    break;
  case PCRE_ERROR_BADCOUNT:
    errmsg= "pcre_exec: ovesize is negative";
    break;
  case PCRE_ERROR_RECURSIONLIMIT:
    my_snprintf(buf, sizeof(buf), "pcre_exec: recursion limit of %ld exceeded",
                m_pcre_extra.match_limit_recursion);
    errmsg= buf;
    break;
  case PCRE_ERROR_BADNEWLINE:
    errmsg= "pcre_exec: bad newline options";
    break;
  case PCRE_ERROR_BADOFFSET:
    errmsg= "pcre_exec: start offset negative or greater than string length";
    break;
  case PCRE_ERROR_SHORTUTF8:
    errmsg= "pcre_exec: ended in middle of utf8 sequence";
    break;
  case PCRE_ERROR_JIT_STACKLIMIT:
    errmsg= "pcre_exec: insufficient stack memory for JIT compile";
    break;
  case PCRE_ERROR_RECURSELOOP:
    errmsg= "pcre_exec: Recursion loop detected";
    break;
  case PCRE_ERROR_BADMODE:
    errmsg= "pcre_exec: compiled pattern passed to wrong bit library function";
    break;
  case PCRE_ERROR_BADENDIANNESS:
    errmsg= "pcre_exec: compiled pattern passed to wrong endianness processor";
    break;
  case PCRE_ERROR_JIT_BADOPTION:
    errmsg= "pcre_exec: bad jit option";
    break;
  case PCRE_ERROR_BADLENGTH:
    errmsg= "pcre_exec: negative length";
    break;
  default:
    /*
      As other error codes should normally not happen,
      we just report the error code without textual description
      of the code.
    */
    my_snprintf(buf, sizeof(buf), "pcre_exec: Internal error (%d)", rc);
    errmsg= buf;
  }
  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                      ER_REGEXP_ERROR, ER_THD(thd, ER_REGEXP_ERROR), errmsg);
}


void Item_in_optimizer::print(String *str, enum_query_type query_type)
{
  if (query_type & QT_PARSABLE)
    args[1]->print(str, query_type);
  else
  {
     restore_first_argument();
     Item_func::print(str, query_type);
  }
}


  void quick_fix_field()
  {
    /*
      We can get here when Item_bool is created instead of a constant
      predicate at various condition optimization stages in sql_select.
    */
  }


void Item_func_not_all::print(String *str, enum_query_type query_type)
{
  if (show)
    Item_func::print(str, query_type);
  else
    args[0]->print(str, query_type);
}


bool cmp_item_row::
      aggregate_row_elements_for_comparison(THD *thd,
                                            Type_handler_hybrid_field_type *cmp,
                                            Item_args *tmp,
                                            const char *funcname,
                                            uint col,
                                            uint level)
{
  DBUG_EXECUTE_IF("cmp_item",
  {
    for (uint i= 0 ; i < tmp->argument_count(); i++)
    {
      Item *arg= tmp->arguments()[i];
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
                          ER_UNKNOWN_ERROR, "DBUG: %s[%d,%d] handler=%s",
                          String_space(level).c_ptr(), col, i,
                          arg->type_handler()->name().ptr());
    }
  }
  );
  bool err= cmp->aggregate_for_comparison(funcname, tmp->arguments(),
                                          tmp->argument_count(), true);
  DBUG_EXECUTE_IF("cmp_item",
  {
    if (!err)
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
                          ER_UNKNOWN_ERROR, "DBUG: %s=> handler=%s",
                          String_space(level).c_ptr(),
                          cmp->type_handler()->name().ptr());
  }
  );
  return err;
}


bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
{
  DBUG_ASSERT(fixed == 0);
  Item_subselect *sub= 0;
  uint col;

  /*
     MAX/MIN optimization can convert the subquery into
     expr + Item_singlerow_subselect
   */
  if (args[1]->type() == Item::SUBSELECT_ITEM)
    sub= (Item_subselect *)args[1];

  if (fix_left(thd))
    return TRUE;
  if (args[0]->maybe_null)
    maybe_null=1;

  if (args[1]->fix_fields_if_needed(thd, args + 1))
    return TRUE;
  if (!invisible_mode() &&
      ((sub && ((col= args[0]->cols()) != sub->engine->cols())) ||
       (!sub && (args[1]->cols() != (col= 1)))))
  {
    my_error(ER_OPERAND_COLUMNS, MYF(0), col);
    return TRUE;
  }
  if (args[1]->maybe_null)
    maybe_null=1;
  m_with_subquery= true;
  join_with_sum_func(args[1]);
  with_window_func= args[0]->with_window_func;
  // The subquery cannot have window functions aggregated in this select
  DBUG_ASSERT(!args[1]->with_window_func);
  with_field= with_field || args[1]->with_field;
  with_param= args[0]->with_param || args[1]->with_param;
  used_tables_and_const_cache_join(args[1]);
  fixed= 1;
  return FALSE;
}


uchar *in_time::get_value(Item *item)
{
  tmp.val= item->val_time_packed(current_thd);
  if (item->null_value)
    return 0;
  tmp.unsigned_flag= 1L;
  return (uchar*) &tmp;
}


  const Type_handler *cast_to_int_type_handler() const
  {
    return real_type_handler()->cast_to_int_type_handler();
  }


uchar *in_string::get_value(Item *item)
{
  return (uchar*) item->val_str(&tmp);
}


bool Arg_comparator::set_cmp_func_int()
{
  THD *thd= current_thd;
  func= is_owner_equal_func() ? &Arg_comparator::compare_e_int :
                                &Arg_comparator::compare_int_signed;
  if ((*a)->field_type() == MYSQL_TYPE_YEAR &&
      (*b)->field_type() == MYSQL_TYPE_YEAR)
  {
    func= is_owner_equal_func() ? &Arg_comparator::compare_e_datetime :
                                  &Arg_comparator::compare_datetime;
  }
  else if (func == &Arg_comparator::compare_int_signed)
  {
    if ((*a)->unsigned_flag)
      func= (((*b)->unsigned_flag)?
             &Arg_comparator::compare_int_unsigned :
             &Arg_comparator::compare_int_unsigned_signed);
    else if ((*b)->unsigned_flag)
      func= &Arg_comparator::compare_int_signed_unsigned;
  }
  else if (func== &Arg_comparator::compare_e_int)
  {
    if ((*a)->unsigned_flag ^ (*b)->unsigned_flag)
      func= &Arg_comparator::compare_e_int_diff_signedness;
  }
  a= cache_converted_constant(thd, a, &a_cache, compare_type_handler());
  b= cache_converted_constant(thd, b, &b_cache, compare_type_handler());
  return false;
}


void Item_in_optimizer::cleanup()
{
  DBUG_ENTER("Item_in_optimizer::cleanup");
  Item_bool_func::cleanup();
  if (!save_cache)
    cache= 0;
  expr_cache= 0;
  DBUG_VOID_RETURN;
}


  bool is_longlong() const
  {
    return m_type == DYN_COL_UINT || m_type == DYN_COL_INT;
  }


  const my_decimal *const_ptr_my_decimal() const
  { return can_return_const_value(DECIMAL_RESULT) ? &value.m_decimal : NULL; }


  String *val_str(String *to)
  {
    return m_value.to_datetime(current_thd).to_string(to, decimals);
  }


With_sum_func_cache* get_with_sum_func_cache() { return this; }


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


  bool has_int_value() const
  {
    return state == SHORT_DATA_VALUE &&
           value.type_handler()->cmp_type() == INT_RESULT;
  }


  bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
  {
    return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
  }


  virtual longlong val_time_packed(THD *thd)
  {
    return Time(thd, this, Time::Options_cmp(thd)).to_packed();
  }


int Arg_comparator::compare_real()
{
  /*
    Fix yet another manifestation of Bug#2338. 'Volatile' will instruct
    gcc to flush double values out of 80-bit Intel FPU registers before
    performing the comparison.
  */
  volatile double val1, val2;
  val1= (*a)->val_real();
  if (!(*a)->null_value)
  {
    val2= (*b)->val_real();
    if (!(*b)->null_value)
    {
      if (set_null)
        owner->null_value= 0;
      if (val1 < val2)	return -1;
      if (val1 == val2) return 0;
      return 1;
    }
  }
  if (set_null)
    owner->null_value= 1;
  return -1;
}


  With_sum_func_cache()
   :m_with_sum_func(false)
  { }


  longlong val_datetime_packed(THD *thd)
  {
    return update_null() ? 0 : cached_time.valid_date_to_packed();
  }


  bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
  {
    illegal_method_call((const char*)"val_decimal");
    return true;
  }


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


String *val_str(String *to) { return decimal_value.to_string(to); }


bool is_double() const { return m_type == DYN_COL_DOUBLE; }


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


int Item_func_nullif::compare()
{
  if (m_cache)
    m_cache->cache_value();
  return cmp.compare();
}


bool cmp_item_row::prepare_comparators(THD *thd, const char *funcname,
                                       const Item_args *args, uint level)
{
  DBUG_EXECUTE_IF("cmp_item",
                  push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
                  ER_UNKNOWN_ERROR, "DBUG: %sROW(%d args) level=%d",
                  String_space(level).c_ptr(),
                  args->argument_count(), level););
  DBUG_ASSERT(args->argument_count() > 0);
  if (alloc_comparators(thd, args->arguments()[0]->cols()))
    return true;
  DBUG_ASSERT(n == args->arguments()[0]->cols());
  for (uint col= 0; col < n; col++)
  {
    Item_args tmp;
    Type_handler_hybrid_field_type cmp;

    if (tmp.alloc_and_extract_row_elements(thd, args, col) ||
        aggregate_row_elements_for_comparison(thd, &cmp, &tmp,
                                              funcname, col, level + 1))
      return true;

    /*
      There is a legacy bug (MDEV-11511) in the code below,
      which should be fixed eventually.
      When performing:
       (predicant0,predicant1) IN ((value00,value01),(value10,value11))
      It uses only the data type and the collation of the predicant
      elements only. It should be fixed to take into account the data type and
      the collation for all elements at the N-th positions of the
      predicate and all values:
      - predicate0, value00, value01
      - predicate1, value10, value11
    */
    Item *item0= args->arguments()[0]->element_index(col);
    CHARSET_INFO *collation= item0->collation.collation;
    if (!(comparators[col]= cmp.type_handler()->make_cmp_item(thd, collation)))
      return true;
    if (cmp.type_handler() == &type_handler_row)
    {
      // Prepare comparators for ROW elements recursively
      cmp_item_row *row= static_cast<cmp_item_row*>(comparators[col]);
      if (row->prepare_comparators(thd, funcname, &tmp, level + 1))
        return true;
    }
  }
  return false;
}


void Item_func_isnull::print(String *str, enum_query_type query_type)
{
  if (const_item() && !args[0]->maybe_null &&
      !(query_type & (QT_NO_DATA_EXPANSION | QT_VIEW_INTERNAL)))
    str->append("/*always not null*/ 1");
  else
    args[0]->print_parenthesised(str, query_type, precedence());
  str->append(STRING_WITH_LEN(" is null"));
}


With_subquery_cache(): m_with_subquery(false) { }


Item_func_nullif::int_op()
{
  DBUG_ASSERT(fixed == 1);
  longlong value;
  if (!compare())
  {
    null_value=1;
    return 0;
  }
  value= args[2]->val_int();
  null_value= args[2]->null_value;
  return value;
}


virtual Item *get_item() { return example; }


  void set_geometry_type(uint type)
  {
    DBUG_ASSERT(type <= m_geometry_type_unknown);
    m_geometry_type= type;
  }


Field *field() const { return m_field; }


  Field *create_field_for_create_select(TABLE *table)
  { return create_table_field_from_handler(table); }


in_string::in_string(THD *thd, uint elements, qsort2_cmp cmp_func,
                     CHARSET_INFO *cs)
  :in_vector(thd, elements, sizeof(String), cmp_func, cs),
   tmp(buff, sizeof(buff), &my_charset_bin)
{}


my_decimal *val_decimal(my_decimal *to) { return cached_time.to_decimal(to); }


void Item_func_not::print(String *str, enum_query_type query_type)
{
  str->append('!');
  args[0]->print_parenthesised(str, query_type, precedence());
}


  With_sum_func_cache(const Item *a, const Item *b, const Item *c)
   :m_with_sum_func(a->with_sum_func() || b->with_sum_func() ||
                    c->with_sum_func())
  { }


  const Type_handler *type_handler() const
  {
    DBUG_ASSERT(0);
    return &type_handler_null;
  }


  uint decimal_scale() const
  {
    return type_handler()->Item_decimal_scale(this);
  }


  Type_geometry_attributes(const Type_handler *handler,
                           const Type_all_attributes *gattr)
   :m_geometry_type(m_geometry_type_unknown)
  {
    copy(handler, gattr);
  }


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


Item_bool_rowready_func2 *Eq_creator::create(THD *thd, Item *a, Item *b) const
{
  return new(thd->mem_root) Item_func_eq(thd, a, b);
}


longlong Item_func_between::val_int_cmp_datetime()
{
  THD *thd= current_thd;
  longlong value= args[0]->val_datetime_packed(thd), a, b;
  if ((null_value= args[0]->null_value))
    return 0;
  a= args[1]->val_datetime_packed(thd);
  b= args[2]->val_datetime_packed(thd);
  return val_int_cmp_int_finalize(value, a, b);
}


inline void TABLE::mark_virtual_column_deps(Field *field)
{
  DBUG_ASSERT(field->vcol_info);
  DBUG_ASSERT(field->vcol_info->expr);
  field->vcol_info->expr->walk(&Item::register_field_in_read_map, 1, 0);
}


int cmp_item_timestamp::compare(cmp_item *arg)
{
  cmp_item_timestamp *tmp= static_cast<cmp_item_timestamp*>(arg);
  return type_handler_timestamp2.cmp_native(m_native, tmp->m_native);
}


  void copy(const Type_handler *handler, const Type_all_attributes *gattr)
  {
    // Ignore implicit NULLs
    m_geometry_type= handler == &type_handler_geometry ?
                     gattr->uint_geometry_type() :
                     m_geometry_type_unknown;
  }


bool Item_func_in::fix_for_row_comparison_using_bisection(THD *thd)
{
  if (unlikely(!(array= new (thd->mem_root) in_row(thd, arg_count-1, 0))))
    return true;
  cmp_item_row *cmp= &((in_row*)array)->tmp;
  if (cmp->prepare_comparators(thd, func_name(), this, 0))
    return true;
  fix_in_vector();
  return false;
}


int Arg_comparator::compare_int_signed_unsigned()
{
  longlong sval1= (*a)->val_int();
  if (!(*a)->null_value)
  {
    ulonglong uval2= (ulonglong)(*b)->val_int();
    if (!(*b)->null_value)
    {
      if (set_null)
        owner->null_value= 0;
      if (sval1 < 0 || (ulonglong)sval1 < uval2)
        return -1;
      if ((ulonglong)sval1 == uval2)
        return 0;
      return 1;
    }
  }
  if (set_null)
    owner->null_value= 1;
  return -1;
}


virtual Item* build_clone(THD *thd) { return get_copy(thd); }


MDEV-26323 use-after-poison issue of MariaDB server

static int check_func_long(THD *thd, struct st_mysql_sys_var *var,
                          void *save, st_mysql_value *value)
{
  my_bool fixed1, fixed2;
  long long orig, val;
  struct my_option options;
  value->val_int(value, &orig);
  val= orig;
  plugin_opt_set_limits(&options, var);

  if (var->flags & PLUGIN_VAR_UNSIGNED)
  {
    if ((fixed1= (!value->is_unsigned(value) && val < 0)))
      val=0;
    *(ulong *)save= (ulong) getopt_ull_limit_value((ulonglong) val, &options,
                                                   &fixed2);
  }
  else
  {
    if ((fixed1= (value->is_unsigned(value) && val < 0)))
      val=LONGLONG_MAX;
    *(long *)save= (long) getopt_ll_limit_value(val, &options, &fixed2);
  }

  return throw_bounds_warning(thd, var->name, fixed1 || fixed2,
                              value->is_unsigned(value), (longlong) orig);
}

MariaDB Server v10.6 and below was discovered to contain an use-after-free in the component my_strcasecmp_8bit, which is exploited via specially crafted SQL statements.