  virtual enum_field_types binlog_type() const
  {
    /*
      Binlog stores field->type() as type code by default. For example,
      it puts MYSQL_TYPE_STRING in case of CHAR, VARCHAR, SET and ENUM,
      with extra data type details put into metadata.

      Binlog behaviour slightly differs between various MySQL and MariaDB
      versions for the temporal data types TIME, DATETIME and TIMESTAMP.

      MySQL prior to 5.6 uses MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME
      and MYSQL_TYPE_TIMESTAMP type codes in binlog and stores no
      additional metadata.

      MariaDB-5.3 implements new versions for TIME, DATATIME, TIMESTAMP
      with fractional second precision, but uses the old format for the
      types TIME(0), DATETIME(0), TIMESTAMP(0), and it still stores
      MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP in binlog,
      with no additional metadata.
      So row-based replication between temporal data types of
      different precision is not possible in MariaDB.

      MySQL-5.6 also implements a new version of TIME, DATETIME, TIMESTAMP
      which support fractional second precision 0..6, and use the new
      format even for the types TIME(0), DATETIME(0), TIMESTAMP(0).
      For these new data types, MySQL-5.6 stores new type codes
      MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2, MYSQL_TYPE_TIMESTAMP2 in binlog,
      with fractional precision 0..6 put into metadata.
      This makes it in theory possible to do row-based replication between
      columns of different fractional precision (e.g. from TIME(1) on master
      to TIME(6) on slave). However, it's not currently fully implemented yet.
      MySQL-5.6 can only do row-based replication from the old types
      TIME, DATETIME, TIMESTAMP (represented by MYSQL_TYPE_TIME,
      MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP type codes in binlog)
      to the new corresponding types TIME(0), DATETIME(0), TIMESTAMP(0).

      Note: MariaDB starting from the version 10.0 understands the new
      MySQL-5.6 type codes MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2,
      MYSQL_TYPE_TIMESTAMP2. When started over MySQL-5.6 tables both on
      master and on slave, MariaDB-10.0 can also do row-based replication
      from the old types TIME, DATETIME, TIMESTAMP to the new MySQL-5.6
      types TIME(0), DATETIME(0), TIMESTAMP(0).

      Note: perhaps binlog should eventually be modified to store
      real_type() instead of type() for all column types.
    */
    return type();
  }


  bool maybe_null_in_table() const
  { return null_ptr >= table->record[0] && null_ptr <= ptr; }


  uint32 max_display_length() const
  {
    return type_limits_int()->char_length();
  }


int Field_decimal::store(double nr)
{
  ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
  if (unsigned_flag && nr < 0)
  {
    overflow(1);
    return 1;
  }

  if (!std::isfinite(nr)) // Handle infinity as special case
  {
    overflow(nr < 0.0);
    return 1;
  }

  size_t length;
  uchar fyllchar,*to;
  char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];

  fyllchar = zerofill ? (char) '0' : (char) ' ';
  length= my_fcvt(nr, dec, buff, NULL);

  if (length > field_length)
  {
    overflow(nr < 0.0);
    return 1;
  }
  else
  {
    to=ptr;
    for (size_t i=field_length-length ; i-- > 0 ;)
      *to++ = fyllchar;
    memcpy(to,buff,length);
    return 0;
  }
}


void Field_long::sql_type(String &res) const
{
  CHARSET_INFO *cs=res.charset();
  res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
			  "int(%d)",(int) field_length));
  add_zerofill_and_unsigned(res);
}


int truncate_double(double *nr, uint field_length, uint dec,
                    bool unsigned_flag, double max_value)
{
  int error= 0;
  double res= *nr;

  if (std::isnan(res))
  {
    *nr= 0;
    return -1;
  }
  else if (unsigned_flag && res < 0)
  {
    *nr= 0;
    return 1;
  }

  if (dec < FLOATING_POINT_DECIMALS)
  {
    uint order= field_length - dec;
    uint step= array_elements(log_10) - 1;
    double max_value_by_dec= 1.0;
    for (; order > step; order-= step)
      max_value_by_dec*= log_10[step];
    max_value_by_dec*= log_10[order];
    max_value_by_dec-= 1.0 / log_10[dec];
    set_if_smaller(max_value, max_value_by_dec);

    /* Check for infinity so we don't get NaN in calculations */
    if (!std::isinf(res))
    {
      double tmp= rint((res - floor(res)) * log_10[dec]) / log_10[dec];
      res= floor(res) + tmp;
    }
  }

  if (res < -max_value)
  {
    res= -max_value;
    error= 1;
  }
  else if (res > max_value)
  {
    res= max_value;
    error= 1;
  }

  *nr= res;
  return error;
}


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


longlong Field_datetime::val_int(void)
{
  ASSERT_COLUMN_MARKED_FOR_READ;
  longlong j;
  j=sint8korr(ptr);
  return j;
}


bool val_bool() { return val_int() != 0; }


CHARSET_INFO *charset(void) const { return &my_charset_numeric; }


int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
  longlong a,b;
  a=sint8korr(a_ptr);
  b=sint8korr(b_ptr);
  if (unsigned_flag)
    return ((ulonglong) a < (ulonglong) b) ? -1 :
    ((ulonglong) a > (ulonglong) b) ? 1 : 0;
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}


double Field_datetime_with_dec::val_real(void)
{
  MYSQL_TIME ltime;
  get_date(&ltime, 0);
  return TIME_to_double(&ltime);
}


String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
				 String *val_ptr)
{
  ASSERT_COLUMN_MARKED_FOR_READ;
  val_ptr->set((const char*) get_data(), get_length(), field_charset);
  return val_ptr;
}


void Field_time::sort_string(uchar *to,uint length __attribute__((unused)))
{
  to[0] = (uchar) (ptr[2] ^ 128);
  to[1] = ptr[1];
  to[2] = ptr[0];
}


  virtual bool update_max(Field *max_val, bool force_update)
  {
    bool update_fl= force_update || cmp(ptr, max_val->ptr) > 0;
    if (update_fl)
    {
      max_val->set_notnull();
      memcpy(max_val->ptr, ptr, pack_length());
    }
    return update_fl;
  }


void Field_decimal::overflow(bool negative)
{
  uint len=field_length;
  uchar *to=ptr, filler= '9';

  set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
  if (negative)
  {
    if (!unsigned_flag)
    {
      /* Put - sign as a first digit so we'll have -999..999 or 999..999 */
      *to++ = '-';
      len--;
    }
    else
    {
      filler= '0';				// Fill up with 0
      if (!zerofill)
      {
	/*
	  Handle unsigned integer without zerofill, in which case
	  the number should be of format '   0' or '   0.000'
	*/
	uint whole_part=field_length- (dec ? dec+2 : 1);
	// Fill with spaces up to the first digit
	bfill(to, whole_part, ' ');
	to+=  whole_part;
	len-= whole_part;
	// The main code will also handle the 0 before the decimal point
      }
    }
  }
  bfill(to, len, filler);
  if (dec)
    ptr[field_length-dec-1]='.';
  return;
}


Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
                     uchar null_bit_arg, utype unireg_check_arg,
                     const LEX_CSTRING *field_name_arg,
                     const DTCollation &collation)
  :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
         unireg_check_arg, field_name_arg)
{
  field_charset= collation.collation;
  if (collation.collation->state & MY_CS_BINSORT)
    flags|=BINARY_FLAG;
  field_derivation= collation.derivation;
  field_repertoire= collation.repertoire;
}


bool Field_row::sp_prepare_and_store_item(THD *thd, Item **value)
{
  DBUG_ENTER("Field_row::sp_prepare_and_store_item");

  if (value[0]->type() == Item::NULL_ITEM)
  {
    /*
      We're in a auto-generated sp_inst_set, to assign
      the explicit default NULL value to a ROW variable.
    */
    m_table->set_all_fields_to_null();
    DBUG_RETURN(false);
  }

  /**
    - In case if we're assigning a ROW variable from another ROW variable,
      value[0] points to Item_splocal. sp_fix_func_item() will return the
      fixed underlying Item_field pointing to Field_row.
    - In case if we're assigning from a ROW() value, src and value[0] will
      point to the same Item_row.
  */
  Item *src;
  if (!(src= thd->sp_fix_func_item(value)) ||
      src->cmp_type() != ROW_RESULT ||
      src->cols() != m_table->s->fields)
  {
    my_error(ER_OPERAND_COLUMNS, MYF(0), m_table->s->fields);
    m_table->set_all_fields_to_null();
    DBUG_RETURN(true);
  }

  DBUG_RETURN(m_table->sp_set_all_fields_from_item(thd, src));
}


int Field_tiny::store(double nr)
{
  ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
  int error= 0;
  nr=rint(nr);
  if (unsigned_flag)
  {
    if (nr < 0.0)
    {
      *ptr=0;
      set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
      error= 1;
    }
    else if (nr > 255.0)
    {
      *ptr= (uchar) 255;
      set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
      error= 1;
    }
    else
      *ptr= (uchar) nr;
  }
  else
  {
    if (nr < -128.0)
    {
      *ptr= (uchar) -128;
      set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
      error= 1;
    }
    else if (nr > 127.0)
    {
      *ptr=127;
      set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
      error= 1;
    }
    else
      *ptr=(uchar) (int) nr;
  }
  return error;
}


  Field_double(uint32 len_arg, bool maybe_null_arg,
               const LEX_CSTRING *field_name_arg,
	       uint8 dec_arg, bool not_fixed_arg)
    :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
                NONE, field_name_arg, dec_arg, 0, 0)
    {
      not_fixed= not_fixed_arg;
      if (dec_arg >= FLOATING_POINT_DECIMALS)
        dec_arg= NOT_FIXED_DEC;
    }


check_field_for_37426(const void *param_arg)
{
  Check_field_param *param= (Check_field_param*) param_arg;
  DBUG_ASSERT(param->field->real_type() == MYSQL_TYPE_STRING);
  DBUG_PRINT("debug", ("Field %s - type: %d, size: %d",
                       param->field->field_name.str,
                       param->field->real_type(),
                       param->field->row_pack_length()));
  return param->field->row_pack_length() > 255;
}


int Field_varstring::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
                                uint32 max_length)
{
  uint32 a_length,b_length;

  if (length_bytes == 1)
  {
    a_length= (uint) *a_ptr;
    b_length= (uint) *b_ptr;
  }
  else
  {
    a_length= uint2korr(a_ptr);
    b_length= uint2korr(b_ptr);
  }
  set_if_smaller(a_length, max_length);
  set_if_smaller(b_length, max_length);
  if (a_length != b_length)
    return 1;
  return memcmp(a_ptr+length_bytes, b_ptr+length_bytes, a_length);
}


Field_bit_as_char::Field_bit_as_char(uchar *ptr_arg, uint32 len_arg,
                                     uchar *null_ptr_arg, uchar null_bit_arg,
                                     enum utype unireg_check_arg,
                                     const LEX_CSTRING *field_name_arg)
  :Field_bit(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, 0, 0,
             unireg_check_arg, field_name_arg)
{
  flags|= UNSIGNED_FLAG;
  bit_len= 0;
  bytes_in_rec= (len_arg + 7) / 8;
}


int Field_blob::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
  uchar *blob1,*blob2;
  memcpy(&blob1, a_ptr+packlength, sizeof(char*));
  memcpy(&blob2, b_ptr+packlength, sizeof(char*));
  size_t a_len= get_length(a_ptr), b_len= get_length(b_ptr);
  return cmp(blob1, (uint32)a_len, blob2, (uint32)b_len);
}


enum Derivation derivation(void) const { return field_derivation; }


  void set_stored_in_db_flag(bool stored)
  {
    stored_in_db= stored;
  }


double Field_datetime::val_real(void)
{
  return (double) Field_datetime::val_int();
}


static void calc_datetime_days_diff(MYSQL_TIME *ltime, long days)
{
  long daydiff= calc_daynr(ltime->year, ltime->month, ltime->day) - days;
  ltime->year= ltime->month= 0;
  if (daydiff >=0 )
  {
    ltime->day= daydiff;
    ltime->time_type= MYSQL_TIMESTAMP_TIME;
  }
  else
  {
    longlong timediff= ((((daydiff        * 24LL +
                           ltime->hour)   * 60LL +
                           ltime->minute) * 60LL +
                           ltime->second) * 1000000LL +
                           ltime->second_part);
    unpack_time(timediff, ltime, MYSQL_TIMESTAMP_TIME);
  }
}


int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }


Field::set_warning(Sql_condition::enum_warning_level level, uint code,
                   int cut_increment, ulong current_row) const
{
  /*
    If this field was created only for type conversion purposes it
    will have table == NULL.
  */
  THD *thd= get_thd();
  if (thd->count_cuted_fields > CHECK_FIELD_EXPRESSION)
  {
    thd->cuted_fields+= cut_increment;
    push_warning_printf(thd, level, code, ER_THD(thd, code), field_name.str,
                        current_row ? current_row
                        : thd->get_stmt_da()->current_row_for_warning());
    return 0;
  }
  return level >= Sql_condition::WARN_LEVEL_WARN;
}


  Field_long(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
	     uchar null_bit_arg,
	     enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
	     bool zero_arg, bool unsigned_arg)
    :Field_int(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
               unireg_check_arg, field_name_arg, zero_arg, unsigned_arg)
    {}


virtual bool zero_pack() const { return 0; }


Field *Field::new_key_field(MEM_ROOT *root, TABLE *new_table,
                            uchar *new_ptr, uint32 length,
                            uchar *new_null_ptr, uint new_null_bit)
{
  Field *tmp;
  if ((tmp= make_new_field(root, new_table, table == new_table)))
  {
    tmp->ptr=      new_ptr;
    tmp->null_ptr= new_null_ptr;
    tmp->null_bit= new_null_bit;
  }
  return tmp;
}


  Field_medium(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
	      uchar null_bit_arg,
	      enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
	      bool zero_arg, bool unsigned_arg)
    :Field_int(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
               unireg_check_arg, field_name_arg, zero_arg, unsigned_arg)
    {}


  Field_short(uint32 len_arg,bool maybe_null_arg,
              const LEX_CSTRING *field_name_arg,
	      bool unsigned_arg)
    :Field_int((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
               NONE, field_name_arg, 0, unsigned_arg)
    {}


double Field_enum::val_real(void)
{
  return (double) Field_enum::val_int();
}


uint32 pack_length() const { return (uint32) bin_size; }


String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
			       String *val_ptr)
{
  ASSERT_COLUMN_MARKED_FOR_READ;
  uchar *str;
  size_t tmp_length;

  for (str=ptr ; *str == ' ' ; str++) ;
  val_ptr->set_charset(&my_charset_numeric);
  tmp_length= (size_t) (str-ptr);
  if (field_length < tmp_length)		// Error in data
    val_ptr->length(0);
  else
    val_ptr->set_ascii((const char*) str, field_length-tmp_length);
  return val_ptr;
}


bool Item_default_value::fix_fields(THD *thd, Item **items)
{
  Item *real_arg;
  Item_field *field_arg;
  Field *def_field;
  DBUG_ASSERT(fixed == 0);
  DBUG_ASSERT(arg);

  /*
    DEFAULT() do not need table field so should not ask handler to bring
    field value (mark column for read)
  */
  enum_column_usage save_column_usage= thd->column_usage;
  /*
    Fields which has defult value could be read, so it is better hide system
    invisible columns.
  */
  thd->column_usage= COLUMNS_WRITE;
  if (arg->fix_fields_if_needed(thd, &arg))
  {
    thd->column_usage= save_column_usage;
    goto error;
  }
  thd->column_usage= save_column_usage;

  real_arg= arg->real_item();
  if (real_arg->type() != FIELD_ITEM)
  {
    my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name.str);
    goto error;
  }

  field_arg= (Item_field *)real_arg;
  if ((field_arg->field->flags & NO_DEFAULT_VALUE_FLAG))
  {
    my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0),
             field_arg->field->field_name.str);
    goto error;
  }
  if (!(def_field= (Field*) thd->alloc(field_arg->field->size_of())))
    goto error;
  cached_field= def_field;
  memcpy((void *)def_field, (void *)field_arg->field,
         field_arg->field->size_of());
  def_field->reset_fields();
  // If non-constant default value expression or a blob
  if (def_field->default_value &&
      (def_field->default_value->flags || (def_field->flags & BLOB_FLAG)))
  {
    uchar *newptr= (uchar*) thd->alloc(1+def_field->pack_length());
    if (!newptr)
      goto error;
    if (should_mark_column(thd->column_usage))
      def_field->default_value->expr->update_used_tables();
    def_field->move_field(newptr+1, def_field->maybe_null() ? newptr : 0, 1);
  }
  else
    def_field->move_field_offset((my_ptrdiff_t)
                                 (def_field->table->s->default_values -
                                  def_field->table->record[0]));
  set_field(def_field);
  return FALSE;

error:
  context->process_error(thd);
  return TRUE;
}


void Field_timestamp_hires::store_TIME(my_time_t timestamp, ulong sec_part)
{
  mi_int4store(ptr, timestamp);
  store_bigendian(sec_part_shift(sec_part, dec), ptr+4, sec_part_bytes(dec));
}


Field_longstr::report_if_important_data(const char *pstr, const char *end,
                                        bool count_spaces)
{
  THD *thd;
  if ((pstr < end) &&
      (thd= get_thd())->count_cuted_fields > CHECK_FIELD_EXPRESSION)
  {
    if (test_if_important_data(field_charset, pstr, end))
    {
      if (thd->abort_on_warning)
        set_warning(ER_DATA_TOO_LONG, 1);
      else
        set_warning(WARN_DATA_TRUNCATED, 1);
      return 2;
    }
    else if (count_spaces)
    {
      /* If we lost only spaces then produce a NOTE, not a WARNING */
      set_note(WARN_DATA_TRUNCATED, 1);
      return 2;
    }
  }
  return 0;
}


Field::Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
	     uchar null_bit_arg,
	     utype unireg_check_arg, const LEX_CSTRING *field_name_arg)
  :ptr(ptr_arg), invisible(VISIBLE),
  null_ptr(null_ptr_arg), table(0), orig_table(0),
  table_name(0), field_name(*field_name_arg), option_list(0),
  option_struct(0), key_start(0), part_of_key(0),
  part_of_key_not_clustered(0), part_of_sortkey(0),
  unireg_check(unireg_check_arg), field_length(length_arg),
  null_bit(null_bit_arg), is_created_from_null_item(FALSE),
  read_stats(NULL), collected_stats(0), vcol_info(0), check_constraint(0),
  default_value(0)
{
  flags=null_ptr ? 0: NOT_NULL_FLAG;
  comment.str= (char*) "";
  comment.length=0;
  field_index= 0;
  cond_selectivity= 1.0;
  next_equal_field= NULL;
}


int Field_timestamp::store_decimal(const my_decimal *d)
{
  ulonglong nr;
  ulong sec_part;
  int error;
  MYSQL_TIME ltime;
  longlong tmp;
  THD *thd= get_thd();
  ErrConvDecimal str(d);

  if (my_decimal2seconds(d, &nr, &sec_part))
  {
    tmp= -1;
    error= 2;
  }
  else
    tmp= number_to_datetime(nr, sec_part, &ltime, sql_mode_for_timestamp(thd),
                            &error);
  return store_TIME_with_warning(thd, &ltime, &str, error, tmp != -1);
}


void Field_varstring::mark_unused_memory_as_defined()
{
  uint used_length __attribute__((unused)) = get_length();
  MEM_MAKE_DEFINED(get_data() + used_length, field_length - used_length);
}


  virtual sql_mode_t value_depends_on_sql_mode() const
  {
    return 0;
  }


uint Field_new_decimal::is_equal(Create_field *new_field)
{
  return ((new_field->type_handler() == type_handler()) &&
          ((new_field->flags & UNSIGNED_FLAG) ==
           (uint) (flags & UNSIGNED_FLAG)) &&
          ((new_field->flags & AUTO_INCREMENT_FLAG) ==
           (uint) (flags & AUTO_INCREMENT_FLAG)) &&
          (new_field->length == max_display_length()) &&
          (new_field->decimals == dec));
}


void Field::error_generated_column_function_is_not_allowed(THD *thd,
                                                           bool error) const
{
  StringBuffer<64> tmp;
  vcol_info->expr->print(&tmp, (enum_query_type)
                               (QT_TO_SYSTEM_CHARSET |
                                QT_ITEM_IDENT_SKIP_DB_NAMES |
                                QT_ITEM_IDENT_SKIP_TABLE_NAMES));
  my_error(ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED,
           MYF(error ? 0 : ME_JUST_WARNING),
           tmp.c_ptr_safe(), vcol_info->get_vcol_type_name(),
           const_cast<const char*>(field_name.str));
}


String *Field_new_decimal::val_str(String *val_buffer,
                                   String *val_ptr __attribute__((unused)))
{
  ASSERT_COLUMN_MARKED_FOR_READ;
  my_decimal decimal_value;
  uint fixed_precision= zerofill ? precision : 0;
  my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
                    fixed_precision, dec, '0', val_buffer);
  val_buffer->set_charset(&my_charset_numeric);
  return val_buffer;
}


int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr)
{
  int32 a,b;
  a=sint4korr(a_ptr);
  b=sint4korr(b_ptr);
  if (unsigned_flag)
    return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
  return (a < b) ? -1 : (a > b) ? 1 : 0;
}


  virtual void store_TIME(my_time_t timestamp, ulong sec_part)
  {
    int4store(ptr,timestamp);
  }


  Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
  {
    return (flags & ZEROFILL_FLAG) ?
           get_equal_zerofill_const_item(thd, ctx, const_item) :
           const_item;
  }


bool Field_vers_trx_id::test_if_equality_guarantees_uniqueness(const Item* item) const
{
  return item->type() == Item::DATE_ITEM;
}


my_decimal *val_decimal(my_decimal *) { return 0; }


  Vcol_expr_context(THD *_thd, TABLE *_table) :
    inited(false),
    thd(_thd),
    table(_table),
    old_lex(thd->lex),
    old_map(table->map),
    save_security_ctx(thd->security_ctx),
    save_sql_mode(thd->variables.sql_mode) {}


  bool memcpy_field_possible(const Field *from) const
  {
    /*
      Cannot do memcpy from a longer field to a shorter field,
      e.g. a DOUBLE(53,10) into a DOUBLE(10,10).
      But it should be OK the other way around.
    */
    return real_type() == from->real_type() &&
           pack_length() == from->pack_length() &&
           is_unsigned() <= from->is_unsigned() &&
           decimals() == from->decimals() &&
           field_length >= from->field_length;
  }


bool Field_num::get_int(CHARSET_INFO *cs, const char *from, size_t len,
                        longlong *rnd, ulonglong unsigned_max,
                        longlong signed_min, longlong signed_max)
{
  char *end;
  int error;

  *rnd= (longlong) cs->cset->strntoull10rnd(cs, from, len,
                                            unsigned_flag, &end,
                                            &error);
  if (unsigned_flag)
  {

    if ((((ulonglong) *rnd > unsigned_max) &&
         (*rnd= (longlong) unsigned_max)) ||
        error == MY_ERRNO_ERANGE)
    {
      goto out_of_range;
    }
  }
  else
  {
    if (*rnd < signed_min)
    {
      *rnd= signed_min;
      goto out_of_range;
    }
    else if (*rnd > signed_max)
    {
      *rnd= signed_max;
      goto out_of_range;
    }
  }
  if (get_thd()->count_cuted_fields > CHECK_FIELD_EXPRESSION &&
      check_int(cs, from, len, end, error))
    return 1;
  return 0;

out_of_range:
  set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
  return 1;
}


int Field_enum::store(double nr)
{
  return Field_enum::store((longlong) nr, FALSE);
}


  Table_ident *table_rowtype_ref() const
  {
    return m_table_rowtype_ref;
  }


  TMP_TABLE_PARAM()
    :copy_field(0), group_parts(0),
     group_length(0), group_null_parts(0),
     using_outer_summary_function(0),
     schema_table(0), materialized_subquery(0), force_not_null_cols(0),
     precomputed_group_by(0),
     force_copy_fields(0), bit_fields_as_long(0), skip_create_table(0)
  {}


  select_union_recursive(THD *thd_arg):
    select_union(thd_arg),
    incr_table(0), first_rec_table_to_update(0), cleanup_count(0)
  { incr_table_param.init(); };


uint field_count(List<Item> &fields) const { return 0; }


  Query_arena_memroot(MEM_ROOT *mem_root_arg, enum enum_state state_arg) :
    Query_arena(mem_root_arg, state_arg)
  {}


  Abort_on_warning_instant_set(THD *thd, bool temporary_value)
   :m_thd(thd), m_save_abort_on_warning(thd->abort_on_warning)
  {
    thd->abort_on_warning= temporary_value;
  }


inline int handler::ha_write_tmp_row(uchar *buf)
{
  int error;
  MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str);
  increment_statistics(&SSV::ha_tmp_write_count);
  TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0,
                { error= write_row(buf); })
  MYSQL_INSERT_ROW_DONE(error);
  return error;
}


  inline Internal_error_handler *get_internal_handler()
  { return m_internal_handler; }


void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,
                          uint key_length, const char *table_name,
                          const char *path)
{
  DBUG_ENTER("init_tmp_table_share");
  DBUG_PRINT("enter", ("table: '%s'.'%s'", key, table_name));

  bzero((char*) share, sizeof(*share));
  /*
    This can't be MY_THREAD_SPECIFIC for slaves as they are freed
    during cleanup() from Relay_log_info::close_temporary_tables()
  */
  init_sql_alloc(&share->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0,
                 MYF(thd->slave_thread ? 0 : MY_THREAD_SPECIFIC));
  share->table_category=         TABLE_CATEGORY_TEMPORARY;
  share->tmp_table=              INTERNAL_TMP_TABLE;
  share->db.str=                 (char*) key;
  share->db.length=		 strlen(key);
  share->table_cache_key.str=    (char*) key;
  share->table_cache_key.length= key_length;
  share->table_name.str=         (char*) table_name;
  share->table_name.length=      strlen(table_name);
  share->path.str=               (char*) path;
  share->normalized_path.str=    (char*) path;
  share->path.length= share->normalized_path.length= strlen(path);
  share->frm_version= 		 FRM_VER_CURRENT;

  share->cached_row_logging_check= 0;           // No row logging

  /*
    table_map_id is also used for MERGE tables to suppress repeated
    compatibility checks.
  */
  share->table_map_id= (ulong) thd->query_id;
  DBUG_VOID_RETURN;
}


  void set_thd(THD *thd_arg)
  {
    /*
      Only called for top-level select_results, usually select_send,
      and for the results of subquery engines
      (select_<something>_subselect).
    */
    DBUG_ASSERT(false); /* purecov: inspected */
  }


const char *Natural_join_column::db_name()
{
  if (view_field)
    return table_ref->view_db.str;

  /*
    Test that TABLE_LIST::db is the same as TABLE_SHARE::db to
    ensure consistency. An exception are I_S schema tables, which
    are inconsistent in this respect.
  */
  DBUG_ASSERT(!strcmp(table_ref->db,
                      table_ref->table->s->db.str) ||
              (table_ref->schema_table &&
               is_infoschema_db(table_ref->table->s->db.str,
                                table_ref->table->s->db.length)) ||
               table_ref->is_materialized_derived());
  return table_ref->db;
}


bool TABLE::insert_all_rows_into_tmp_table(THD *thd,
                                           TABLE *tmp_table,
                                           TMP_TABLE_PARAM *tmp_table_param,
                                           bool with_cleanup)
{
  int write_err= 0;

  DBUG_ENTER("TABLE::insert_all_rows_into_tmp_table");

  if (with_cleanup)
  {
   if ((write_err= tmp_table->file->ha_delete_all_rows()))
      goto err;
  }

  if (file->indexes_are_disabled())
    tmp_table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL);
  file->ha_index_or_rnd_end();

  if (file->ha_rnd_init_with_error(1))
    DBUG_RETURN(1);

  if (tmp_table->no_rows)
    tmp_table->file->extra(HA_EXTRA_NO_ROWS);
  else
  {
    /* update table->file->stats.records */
    file->info(HA_STATUS_VARIABLE);
    tmp_table->file->ha_start_bulk_insert(file->stats.records);
  }

  while (!file->ha_rnd_next(tmp_table->record[0]))
  {
    write_err= tmp_table->file->ha_write_tmp_row(tmp_table->record[0]);
    if (write_err)
    {
      bool is_duplicate;
      if (tmp_table->file->is_fatal_error(write_err, HA_CHECK_DUP) &&
          create_internal_tmp_table_from_heap(thd, tmp_table,
                                              tmp_table_param->start_recinfo,
                                              &tmp_table_param->recinfo,
                                              write_err, 1, &is_duplicate))
	DBUG_RETURN(1);

    }
    if (thd->check_killed())
    {
      thd->send_kill_message();
      goto err_killed;
    }
  }
  if (!tmp_table->no_rows && tmp_table->file->ha_end_bulk_insert())
    goto err;
  DBUG_RETURN(0);

err:
  DBUG_PRINT("error",("Got error: %d",write_err));
  file->print_error(write_err, MYF(0));
err_killed:
  (void) file->ha_rnd_end();
  DBUG_RETURN(1);
}


  select_send(THD *thd_arg):
    select_result(thd_arg), is_result_set_started(FALSE) {}


  inline bool is_stmt_prepare_or_first_sp_execute() const
  { DBUG_ASSERT(0); return Statement::is_stmt_prepare_or_first_sp_execute(); }


  void unregister_wait_for_prior_commit()
  {
    if (waitee)
      unregister_wait_for_prior_commit2();
    else
      wakeup_error= 0;
  }


  bool is_connected()
  {
    /*
      All system threads (e.g., the slave IO thread) are connected but
      not using vio. So this function always returns true for all
      system threads.
    */
    return system_thread || (vio_ok() ? vio_is_connected(net.vio) : FALSE);
  }


inline bool binlog_should_compress(ulong len)
{
  return opt_bin_log_compress &&
    len >= opt_bin_log_compress_min_len;
}


  Internal_error_handler() :
    m_prev_internal_handler(NULL)
  {}


  inline bool is_stmt_execute() const
  { return state == STMT_PREPARED || state == STMT_EXECUTED; }


  Key_part_spec *clone(MEM_ROOT *mem_root) const
  { return new (mem_root) Key_part_spec(*this); }


const THD *get_thd(void) { return thd; }


  Diagnostics_area *get_stmt_da()
  { return m_stmt_da; }


  void wakeup_subsequent_commits(int wakeup_error)
  {
    if (wait_for_commit_ptr)
      wait_for_commit_ptr->wakeup_subsequent_commits(wakeup_error);
  }


  int wait_for_prior_commit()
  {
    if (wait_for_commit_ptr)
      return wait_for_commit_ptr->wait_for_prior_commit(this);
    return 0;
  }


virtual bool can_rollback_data() { return 0; }


  inline void reset_killed()
  {
    /*
      Resetting killed has to be done under a mutex to ensure
      its not done during an awake() call.
    */
    if (killed != NOT_KILLED)
    {
      mysql_mutex_lock(&LOCK_thd_kill);
      killed= NOT_KILLED;
      killed_err= 0;
      mysql_mutex_unlock(&LOCK_thd_kill);
    }
  }


  void abort_result_set()
  {
    result->abort_result_set(); /* purecov: inspected */
  }


  select_materialize_with_stats(THD *thd_arg): select_union(thd_arg)
  { tmp_table_param.init(); }


bool has_invoker() { return invoker_user.length > 0; }


bool TABLE_LIST::prepare_view_security_context(THD *thd)
{
  DBUG_ENTER("TABLE_LIST::prepare_view_security_context");
  DBUG_PRINT("enter", ("table: %s", alias));

  DBUG_ASSERT(!prelocking_placeholder && view);
  if (view_suid)
  {
    DBUG_PRINT("info", ("This table is suid view => load contest"));
    DBUG_ASSERT(view && view_sctx);
    if (acl_getroot(view_sctx, definer.user.str, definer.host.str,
                                definer.host.str, thd->db))
    {
      if ((thd->lex->sql_command == SQLCOM_SHOW_CREATE) ||
          (thd->lex->sql_command == SQLCOM_SHOW_FIELDS))
      {
        push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
                            ER_NO_SUCH_USER,
                            ER_THD(thd, ER_NO_SUCH_USER),
                            definer.user.str, definer.host.str);
      }
      else
      {
        if (thd->security_ctx->master_access & SUPER_ACL)
        {
          my_error(ER_NO_SUCH_USER, MYF(0), definer.user.str, definer.host.str);

        }
        else
        {
          if (thd->password == 2)
            my_error(ER_ACCESS_DENIED_NO_PASSWORD_ERROR, MYF(0),
                     thd->security_ctx->priv_user,
                     thd->security_ctx->priv_host);
          else
            my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
                     thd->security_ctx->priv_user,
                     thd->security_ctx->priv_host,
                     (thd->password ?  ER_THD(thd, ER_YES) :
                      ER_THD(thd, ER_NO)));
        }
        DBUG_RETURN(TRUE);
      }
    }
  }
  DBUG_RETURN(FALSE);

}


  void restore_set_statement_var()
  {
    main_lex.restore_set_statement_var();
  }


  bool check_has_uncommitted_xa() const
  {
    if (xa_state == XA_IDLE ||
        xa_state == XA_PREPARED ||
        xa_state == XA_ROLLBACK_ONLY)
    {
      my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
      return true;
    }
    return false;
  }


  static inline TMP_TABLE_SHARE ***prev_ptr(TMP_TABLE_SHARE *l)
  {
    return &l->tmp_prev;
  }


void TABLE::reset_item_list(List<Item> *item_list) const
{
  List_iterator_fast<Item> it(*item_list);
  for (Field **ptr= field; *ptr; ptr++)
  {
    Item_field *item_field= (Item_field*) it++;
    DBUG_ASSERT(item_field != 0);
    item_field->reset_field(*ptr);
  }
}


  inline binlog_filter_state get_binlog_local_stmt_filter()
  {
    return m_binlog_filter_state;
  }


void set_charset(CHARSET_INFO *cs) { m_charset= cs; }


bool is_json_type() { return (*ref)->is_json_type(); }


int subselect_single_select_engine::get_identifier()
{
  return select_lex->select_number;
}


subselect_rowid_merge_engine::~subselect_rowid_merge_engine()
{
  /* None of the resources below is allocated if there are no ordered keys. */
  if (merge_keys_count)
  {
    my_free(row_num_to_rowid);
    for (uint i= 0; i < merge_keys_count; i++)
      delete merge_keys[i];
    delete_queue(&pq);
    if (tmp_table->file->inited == handler::RND)
      tmp_table->file->ha_rnd_end();
  }
}


uint Item_singlerow_subselect::cols()
{
  return engine->cols();
}


bool Item_exists_subselect::fix_fields(THD *thd, Item **ref)
{
  DBUG_ENTER("Item_exists_subselect::fix_fields");
  if (exists_transformed)
    DBUG_RETURN( !( (*ref)= new (thd->mem_root) Item_int(thd, 1)));
  DBUG_RETURN(Item_subselect::fix_fields(thd, ref));
}


void Item_allany_subselect::no_rows_in_result()
{
  /*
    Subquery predicates outside of the SELECT list must be evaluated in order
    to possibly filter the special result row generated for implicit grouping
    if the subquery is in the HAVING clause.
    If the predicate is constant, we need its actual value in the only result
    row for queries with implicit grouping.
  */
  if (parsing_place != SELECT_LIST || const_item())
    return;
  value= 0;
  null_value= 0;
  was_null= 0;
  make_const();
}


static bool find_inner_outer_equalities(Item **conds,
                                        Dynamic_array<EQ_FIELD_OUTER> &result)
{
  bool found=  FALSE;
  EQ_FIELD_OUTER element;
  if (is_cond_and(*conds))
  {
    List_iterator<Item> li(*((Item_cond*)*conds)->argument_list());
    Item *item;
    bool allow_subselect= true;
    while ((item= li++))
    {
      if (item->type() == Item::FUNC_ITEM &&
          check_equality_for_exist2in((Item_func *)item,
                                      allow_subselect,
                                      &element.local_field,
                                      &element.outer_exp))
      {
        found= TRUE;
        allow_subselect= false;
        element.eq_ref= li.ref();
        if (result.append(element))
          goto alloc_err;
      }
    }
  }
  else if ((*conds)->type() == Item::FUNC_ITEM &&
           check_equality_for_exist2in((Item_func *)*conds,
                                       true,
                                       &element.local_field,
                                       &element.outer_exp))
  {
    found= TRUE;
    element.eq_ref= conds;
    if (result.append(element))
      goto alloc_err;
  }

  return !found;
alloc_err:
  return TRUE;
}


Item_allany_subselect::select_transformer(JOIN *join)
{
  DBUG_ENTER("Item_allany_subselect::select_transformer");
  DBUG_ASSERT((in_strategy & ~(SUBS_MAXMIN_INJECTED | SUBS_MAXMIN_ENGINE |
                               SUBS_IN_TO_EXISTS | SUBS_STRATEGY_CHOSEN)) == 0);
  if (upper_item)
    upper_item->show= 1;
  DBUG_RETURN(select_in_like_transformer(join));
}


void subselect_union_engine::force_reexecution()
{
  unit->executed= false;
}


bool Ordered_key::next_same()
{
  DBUG_ASSERT(key_buff_elements);

  if (cur_key_idx < key_buff_elements - 1)
  {
    /*
      TIMOUR:
      The below is quite inefficient, since as a result we will fetch every
      row (except the last one) twice. There must be a more efficient way,
      e.g. swapping record[0] and record[1], and reading only the new record.
    */
    if (!cmp_keys_by_row_data(key_buff[cur_key_idx], key_buff[cur_key_idx + 1]))
    {
      ++cur_key_idx;
      return TRUE;
    }
  }
  return FALSE;
}


void Item_subselect::fix_after_pullout(st_select_lex *new_parent,
                                       Item **ref, bool merge)
{
  recalc_used_tables(new_parent, TRUE);
  parent_select= new_parent;
}


int Ordered_key::cmp_key_with_search_key(rownum_t row_num)
{
  /* The length in bytes of the rowids (positions) of tmp_table. */
  uint rowid_length= tbl->file->ref_length;
  uchar *cur_rowid= row_num_to_rowid + row_num * rowid_length;
  int __attribute__((unused)) error;
  int cmp_res;

  if ((error= tbl->file->ha_rnd_pos(tbl->record[0], cur_rowid)))
  {
    /* purecov: begin inspected */
    tbl->file->print_error(error, MYF(ME_FATALERROR));  // Sets fatal_error
    return 0;
    /* purecov: end */
  }

  for (uint i= 0; i < key_column_count; i++)
  {
    cmp_res= compare_pred[i]->get_comparator()->compare();
    /* Unlike Arg_comparator::compare_row() here there should be no NULLs. */
    DBUG_ASSERT(!compare_pred[i]->null_value);
    if (cmp_res)
      return (cmp_res > 0 ? 1 : -1);
  }
  return 0;
}


void Item_exists_subselect::no_rows_in_result()
{
  /*
    Subquery predicates outside of the SELECT list must be evaluated in order
    to possibly filter the special result row generated for implicit grouping
    if the subquery is in the HAVING clause.
    If the predicate is constant, we need its actual value in the only result
    row for queries with implicit grouping.
  */
  if (parsing_place != SELECT_LIST || const_item())
    return;
  value= 0;
  null_value= 0;
  make_const();
}


my_bitmap_init_memroot(MY_BITMAP *map, uint n_bits, MEM_ROOT *mem_root)
{
  my_bitmap_map *bitmap_buf;

  if (!(bitmap_buf= (my_bitmap_map*) alloc_root(mem_root,
                                                bitmap_buffer_size(n_bits))) ||
      my_bitmap_init(map, bitmap_buf, n_bits, FALSE))
    return TRUE;
  bitmap_clear_all(map);
  return FALSE;
}


void Item_in_subselect::update_used_tables()
{
  Item_subselect::update_used_tables();
  left_expr->update_used_tables();
  //used_tables_cache |= left_expr->used_tables();
  used_tables_cache= Item_subselect::used_tables() | left_expr->used_tables();
}


uint subselect_single_select_engine::cols()
{
  //psergey-sj-backport: the following assert was gone in 6.0:
  //DBUG_ASSERT(select_lex->join != 0); // should be called after fix_fields()
  //return select_lex->join->fields_list.elements;
  return select_lex->item_list.elements;
}


bool Item_singlerow_subselect::get_date(MYSQL_TIME *ltime,ulonglong fuzzydate)
{
  DBUG_ASSERT(fixed == 1);
  if (forced_const)
  {
    bool val= value->get_date(ltime, fuzzydate);
    null_value= value->null_value;
    return val;
  }
  if (!exec() && !value->null_value)
  {
    null_value= FALSE;
    return value->get_date(ltime, fuzzydate);
  }
  else
  {
    reset();
    DBUG_ASSERT(null_value);
    return 1;
  }
}


Item_maxmin_subselect::Item_maxmin_subselect(THD *thd,
                                             Item_subselect *parent,
					     st_select_lex *select_lex,
					     bool max_arg):
  Item_singlerow_subselect(thd), was_values(TRUE)
{
  DBUG_ENTER("Item_maxmin_subselect::Item_maxmin_subselect");
  max= max_arg;
  init(select_lex,
       new (thd->mem_root) select_max_min_finder_subselect(thd,
             this, max_arg, parent->substype() == Item_subselect::ALL_SUBS));
  max_columns= 1;
  maybe_null= 1;
  max_columns= 1;

  /*
    Following information was collected during performing fix_fields()
    of Items belonged to subquery, which will be not repeated
  */
  used_tables_cache= parent->get_used_tables_cache();
  const_item_cache= parent->const_item();

  DBUG_VOID_RETURN;
}


void Item_maxmin_subselect::cleanup()
{
  DBUG_ENTER("Item_maxmin_subselect::cleanup");
  Item_singlerow_subselect::cleanup();

  /*
    By default it is TRUE to avoid TRUE reporting by
    Item_func_not_all/Item_func_nop_all if this item was never called.

    Engine exec() set it to FALSE by reset_value_registration() call.
    select_max_min_finder_subselect::send_data() set it back to TRUE if some
    value will be found.
  */
  was_values= TRUE;
  DBUG_VOID_RETURN;
}


subselect_table_scan_engine::subselect_table_scan_engine(
  subselect_uniquesubquery_engine *engine_arg,
  TABLE *tmp_table_arg,
  Item_subselect *item_arg,
  select_result_interceptor *result_arg,
  List<Item> *equi_join_conds_arg,
  bool has_covering_null_row_arg,
  bool has_covering_null_columns_arg,
  uint count_columns_with_nulls_arg)
  :subselect_partial_match_engine(engine_arg, tmp_table_arg, item_arg,
                                  result_arg, equi_join_conds_arg,
                                  has_covering_null_row_arg,
                                  has_covering_null_columns_arg,
                                  count_columns_with_nulls_arg)
{}


void subselect_union_engine::cleanup()
{
  DBUG_ENTER("subselect_union_engine::cleanup");
  unit->reinit_exec_mechanism();
  result->cleanup();
  unit->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED;
  for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
    sl->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED;
  DBUG_VOID_RETURN;
}


Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
                                                Item **where_item,
                                                Item **having_item)
{
  SELECT_LEX *select_lex= join->select_lex;
  uint cols_num= left_expr->cols();
  /*
    The non-transformed HAVING clause of 'join' may be stored in two ways
    during JOIN::optimize: this->tmp_having= this->having; this->having= 0;
  */
  Item* join_having= join->having ? join->having : join->tmp_having;
  bool is_having_used= (join_having || select_lex->with_sum_func ||
                        select_lex->group_list.first ||
                        !select_lex->table_list.elements);

  DBUG_ENTER("Item_in_subselect::create_row_in_to_exists_cond");
  DBUG_ASSERT(thd == join->thd);

  *where_item= NULL;
  *having_item= NULL;

  if (is_having_used)
  {
    /* TODO: say here explicitly if the order of AND parts matters or not. */
    Item *item_having_part2= 0;
    for (uint i= 0; i < cols_num; i++)
    {
      DBUG_ASSERT((left_expr->fixed &&

                  select_lex->ref_pointer_array[i]->fixed) ||
                  (select_lex->ref_pointer_array[i]->type() == REF_ITEM &&
                   ((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() ==
                    Item_ref::OUTER_REF));
      if (select_lex->ref_pointer_array[i]->
          check_cols(left_expr->element_index(i)->cols()))
        DBUG_RETURN(true);
      Item *item_eq=
        new (thd->mem_root)
        Item_func_eq(thd, new (thd->mem_root)
                     Item_direct_ref(thd, &select_lex->context,
                                     (*optimizer->get_cache())->
                                     addr(i),
                                     (char *)"<no matter>",
                                     (char *)in_left_expr_name),
                     new (thd->mem_root)
                     Item_ref(thd, &select_lex->context,
                              &select_lex->ref_pointer_array[i],
                              (char *)"<no matter>",
                              (char *)"<list ref>"));
      Item *item_isnull=
        new (thd->mem_root)
        Item_func_isnull(thd,
                         new (thd->mem_root)
                         Item_ref(thd, &select_lex->context,
                                  &select_lex->ref_pointer_array[i],
                                  (char *)"<no matter>",
                                  (char *)"<list ref>"));
      Item *col_item= new (thd->mem_root)
        Item_cond_or(thd, item_eq, item_isnull);
      if (!abort_on_null && left_expr->element_index(i)->maybe_null &&
          get_cond_guard(i))
      {
        disable_cond_guard_for_const_null_left_expr(i);
        if (!(col_item= new (thd->mem_root)
              Item_func_trig_cond(thd, col_item, get_cond_guard(i))))
          DBUG_RETURN(true);
      }
      *having_item= and_items(thd, *having_item, col_item);

      Item *item_nnull_test=
         new (thd->mem_root)
        Item_is_not_null_test(thd, this,
                              new (thd->mem_root)
                              Item_ref(thd, &select_lex->context,
                                       &select_lex->
                                       ref_pointer_array[i],
                                       (char *)"<no matter>",
                                       (char *)"<list ref>"));
      if (!abort_on_null && left_expr->element_index(i)->maybe_null &&
          get_cond_guard(i) )
      {
        disable_cond_guard_for_const_null_left_expr(i);
        if (!(item_nnull_test=
              new (thd->mem_root)
              Item_func_trig_cond(thd, item_nnull_test, get_cond_guard(i))))
          DBUG_RETURN(true);
      }
      item_having_part2= and_items(thd, item_having_part2, item_nnull_test);
      item_having_part2->top_level_item();
    }
    *having_item= and_items(thd, *having_item, item_having_part2);
  }
  else
  {
    for (uint i= 0; i < cols_num; i++)
    {
      Item *item, *item_isnull;
      DBUG_ASSERT((left_expr->fixed &&
                  select_lex->ref_pointer_array[i]->fixed) ||
                  (select_lex->ref_pointer_array[i]->type() == REF_ITEM &&
                   ((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() ==
                    Item_ref::OUTER_REF));
      if (select_lex->ref_pointer_array[i]->
          check_cols(left_expr->element_index(i)->cols()))
        DBUG_RETURN(true);
      item= new (thd->mem_root)
        Item_func_eq(thd,
                     new (thd->mem_root)
                     Item_direct_ref(thd, &select_lex->context,
                                     (*optimizer->get_cache())->
                                     addr(i),
                                     (char *)"<no matter>",
                                     (char *)in_left_expr_name),
                     new (thd->mem_root)
                     Item_direct_ref(thd, &select_lex->context,
                                     &select_lex->
                                     ref_pointer_array[i],
                                     (char *)"<no matter>",
                                     (char *)"<list ref>"));
      if (!abort_on_null && select_lex->ref_pointer_array[i]->maybe_null)
      {
        Item *having_col_item=
          new (thd->mem_root)
          Item_is_not_null_test(thd, this,
                                new (thd->mem_root)
                                Item_ref(thd, &select_lex->context,
                                         &select_lex->ref_pointer_array[i],
                                         (char *)"<no matter>",
                                         (char *)"<list ref>"));

        item_isnull= new (thd->mem_root)
          Item_func_isnull(thd,
                           new (thd->mem_root)
                           Item_direct_ref(thd, &select_lex->context,
                                           &select_lex->
                                           ref_pointer_array[i],
                                           (char *)"<no matter>",
                                           (char *)"<list ref>"));
        item= new (thd->mem_root) Item_cond_or(thd, item, item_isnull);
        if (left_expr->element_index(i)->maybe_null && get_cond_guard(i))
        {
          disable_cond_guard_for_const_null_left_expr(i);
          if (!(item= new (thd->mem_root)
                Item_func_trig_cond(thd, item, get_cond_guard(i))))
            DBUG_RETURN(true);
          if (!(having_col_item= new (thd->mem_root)
                Item_func_trig_cond(thd, having_col_item, get_cond_guard(i))))
            DBUG_RETURN(true);
        }
        *having_item= and_items(thd, *having_item, having_col_item);
      }
      if (!abort_on_null && left_expr->element_index(i)->maybe_null &&
          get_cond_guard(i))
      {
        if (!(item= new (thd->mem_root)
              Item_func_trig_cond(thd, item, get_cond_guard(i))))
          DBUG_RETURN(true);
      }
      *where_item= and_items(thd, *where_item, item);
    }
  }

  if (*where_item)
  {
    if (!(*where_item)->fixed && (*where_item)->fix_fields(thd, 0))
      DBUG_RETURN(true);
    (*where_item)->top_level_item();
  }

  if (*having_item)
  {
    if (!join_having)
      (*having_item)->name= (char*) in_having_cond;
    if (fix_having(*having_item, select_lex))
      DBUG_RETURN(true);
    (*having_item)->top_level_item();
  }

  DBUG_RETURN(false);
}


bool Item_exists_subselect::val_bool()
{
  DBUG_ASSERT(fixed == 1);
  if (!forced_const && exec())
  {
    reset();
    return 0;
  }
  return value != 0;
}


void subselect_uniquesubquery_engine::print(String *str,
                                            enum_query_type query_type)
{
  char *table_name= tab->table->s->table_name.str;
  str->append(STRING_WITH_LEN("<primary_index_lookup>("));
  tab->ref.items[0]->print(str, query_type);
  str->append(STRING_WITH_LEN(" in "));
  if (tab->table->s->table_category == TABLE_CATEGORY_TEMPORARY)
  {
    /*
      Temporary tables' names change across runs, so they can't be used for
      EXPLAIN EXTENDED.
    */
    str->append(STRING_WITH_LEN("<temporary table>"));
  }
  else
    str->append(table_name, tab->table->s->table_name.length);
  KEY *key_info= tab->table->key_info+ tab->ref.key;
  str->append(STRING_WITH_LEN(" on "));
  str->append(key_info->name);
  if (cond)
  {
    str->append(STRING_WITH_LEN(" where "));
    cond->print(str, query_type);
  }
  str->append(')');
}


double Item_in_subselect::val_real()
{
  /*
    As far as Item_in_subselect called only from Item_in_optimizer this
    method should not be used
  */
  DBUG_ASSERT(fixed == 1);
  if (forced_const)
    return value;
  DBUG_ASSERT((engine->uncacheable() & ~UNCACHEABLE_EXPLAIN) ||
              ! engine->is_executed());
  null_value= was_null= FALSE;
  if (exec())
  {
    reset();
    return 0;
  }
  if (was_null && !value)
    null_value= TRUE;
  return (double) value;
}


bool Ordered_key::lookup()
{
  DBUG_ASSERT(key_buff_elements);

  ha_rows lo= 0;
  ha_rows hi= key_buff_elements - 1;
  ha_rows mid;
  int cmp_res;

  while (lo <= hi)
  {
    mid= lo + (hi - lo) / 2;
    cmp_res= cmp_key_with_search_key(key_buff[mid]);
    /*
      In order to find the minimum match, check if the pevious element is
      equal or smaller than the found one. If equal, we need to search further
      to the left.
    */
    if (!cmp_res && mid > 0)
      cmp_res= !cmp_key_with_search_key(key_buff[mid - 1]) ? 1 : 0;

    if (cmp_res == -1)
    {
      /* row[mid] < search_key */
      lo= mid + 1;
    }
    else if (cmp_res == 1)
    {
      /* row[mid] > search_key */
      if (!mid)
        goto not_found;
      hi= mid - 1;
    }
    else
    {
      /* row[mid] == search_key */
      cur_key_idx= mid;
      return TRUE;
    }
  }
not_found:
  cur_key_idx= HA_POS_ERROR;
  return FALSE;
}


Item_param::Item_param(THD *thd, uint pos_in_query_arg):
  Item_basic_value(thd),
  Rewritable_query_parameter(pos_in_query_arg, 1),
  Type_handler_hybrid_field_type(MYSQL_TYPE_VARCHAR),
  state(NO_VALUE),
  /* Don't pretend to be a literal unless value for this item is set. */
  item_type(PARAM_ITEM),
  indicator(STMT_INDICATOR_NONE),
  set_param_func(default_set_param_func),
  m_out_param_info(NULL),
  /*
    Set m_is_settable_routine_parameter to "true" by default.
    This is needed for client-server protocol,
    whose parameters are always settable.
    For dynamic SQL, settability depends on the type of Item passed
    as an actual parameter. See Item_param::set_from_item().
  */
  m_is_settable_routine_parameter(true),
  m_clones(thd->mem_root)
{
  name= (char*) "?";
  /*
    Since we can't say whenever this item can be NULL or cannot be NULL
    before mysql_stmt_execute(), so we assuming that it can be NULL until
    value is set.
  */
  maybe_null= 1;
}


bool Item_field::check_field_expression_processor(void *arg)
{
  Field *org_field= (Field*) arg;
  if (field->flags & NO_DEFAULT_VALUE_FLAG)
    return 0;
  if ((field->default_value && field->default_value->flags) || field->vcol_info)
  {
    if (field == org_field ||
        (!org_field->vcol_info && field->vcol_info) ||
        (((field->vcol_info && org_field->vcol_info) ||
          (!field->vcol_info && !org_field->vcol_info)) &&
         field->field_index >= org_field->field_index))
    {
      my_error(ER_EXPRESSION_REFERS_TO_UNINIT_FIELD,
               MYF(0),
               org_field->field_name, field->field_name);
      return 1;
    }
  }
  return 0;
}


Item_decimal::Item_decimal(THD *thd, const char *str, const my_decimal *val_arg,
                           uint decimal_par, uint length):
  Item_num(thd)
{
  my_decimal2decimal(val_arg, &decimal_value);
  name= (char*) str;
  decimals= (uint8) decimal_par;
  max_length= length;
  fixed= 1;
}


Item *Item::const_charset_converter(THD *thd, CHARSET_INFO *tocs,
                                    bool lossless,
                                    const char *func_name)
{
  DBUG_ASSERT(const_item());
  DBUG_ASSERT(fixed);
  StringBuffer<64>tmp;
  String *s= val_str(&tmp);
  MEM_ROOT *mem_root= thd->mem_root;

  if (!s)
    return new (mem_root) Item_null(thd, (char *) func_name, tocs);

  if (!needs_charset_converter(s->length(), tocs))
  {
    if (collation.collation == &my_charset_bin && tocs != &my_charset_bin &&
        !this->check_well_formed_result(s, true))
      return NULL;
    return this;
  }

  uint conv_errors;
  Item_string *conv= (func_name ?
                      new (mem_root)
                      Item_static_string_func(thd, func_name,
                                              s, tocs, &conv_errors,
                                              collation.derivation,
                                              collation.repertoire) :
                      new (mem_root)
                      Item_string(thd, s, tocs, &conv_errors,
                                  collation.derivation,
                                  collation.repertoire));

  if (!conv || (conv_errors && lossless))
  {
    /*
      Safe conversion is not possible (or EOM).
      We could not convert a string into the requested character set
      without data loss. The target charset does not cover all the
      characters from the string. Operation cannot be done correctly.
    */
    return NULL;
  }
  if (s->charset() == &my_charset_bin && tocs != &my_charset_bin &&
      !conv->check_well_formed_result(true))
    return NULL;
  return conv;
}


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


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

  if (!item)
    return true;

  if (!fixed)
  {
    if (fix_fields(thd, NULL))
      return true;
  }

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

  field->table->copy_blobs= true;

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

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

  return err_code < 0;
}


Item_sp_variable::Item_sp_variable(THD *thd, char *sp_var_name_str,
                                   uint sp_var_name_length):
  Item(thd), m_thd(0)
#ifndef DBUG_OFF
   , m_sp(0)
#endif
{
  m_name.str= sp_var_name_str;
  m_name.length= sp_var_name_length;
}


Item *Item::safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
  if (!needs_charset_converter(tocs))
    return this;
  Item_func_conv_charset *conv= new (thd->mem_root) Item_func_conv_charset(thd, this, tocs, 1);
  return conv->safe ? conv : NULL;
}


void Item_default_value::calculate()
{
  if (field->default_value)
    field->set_default();
  DEBUG_SYNC(field->table->in_use, "after_Item_default_value_calculate");
}


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


Item *Item_int_with_ref::clone_item(THD *thd)
{
  DBUG_ASSERT(ref->const_item());
  /*
    We need to evaluate the constant to make sure it works with
    parameter markers.
  */
  return (ref->unsigned_flag ?
          new (thd->mem_root)
          Item_uint(thd, ref->name, ref->val_int(), ref->max_length) :
          new (thd->mem_root)
          Item_int(thd, ref->name, ref->val_int(), ref->max_length));
}


bool Item_func_or_sum::agg_item_set_converter(const DTCollation &coll,
                                              const char *fname,
                                              Item **args, uint nargs,
                                              uint flags, int item_sep)
{
  THD *thd= current_thd;
  if (thd->lex->is_ps_or_view_context_analysis())
    return false;
  Item **arg, *safe_args[2]= {NULL, NULL};

  /*
    For better error reporting: save the first and the second argument.
    We need this only if the the number of args is 3 or 2:
    - for a longer argument list, "Illegal mix of collations"
      doesn't display each argument's characteristics.
    - if nargs is 1, then this error cannot happen.
  */
  if (nargs >=2 && nargs <= 3)
  {
    safe_args[0]= args[0];
    safe_args[1]= args[item_sep];
  }

  bool res= FALSE;
  uint i;

  DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());

  for (i= 0, arg= args; i < nargs; i++, arg+= item_sep)
  {
    Item* conv= (*arg)->safe_charset_converter(thd, coll.collation);
    if (conv == *arg)
      continue;

    if (!conv)
    {
      if (nargs >=2 && nargs <= 3)
      {
        /* restore the original arguments for better error message */
        args[0]= safe_args[0];
        args[item_sep]= safe_args[1];
      }
      my_coll_agg_error(args, nargs, fname, item_sep);
      res= TRUE;
      break; // we cannot return here, we need to restore "arena".
    }

    thd->change_item_tree(arg, conv);

    if (conv->fix_fields(thd, arg))
    {
      res= TRUE;
      break; // we cannot return here, we need to restore "arena".
    }
  }
  return res;
}


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


bool Item_ignore_value::send(Protocol *protocol, String *buffer)
{
  DBUG_ASSERT(0); // never should be called
  return TRUE;
}


void Item_field::set_field(Field *field_par)
{
  field=result_field=field_par;			// for easy coding with fields
  maybe_null=field->maybe_null();
  decimals= field->decimals();
  table_name= *field_par->table_name;
  field_name= field_par->field_name;
  db_name= field_par->table->s->db.str;
  alias_name_used= field_par->table->alias_name_used;
  unsigned_flag= MY_TEST(field_par->flags & UNSIGNED_FLAG);
  collation.set(field_par->charset(), field_par->derivation(),
                field_par->repertoire());
  fix_char_length(field_par->char_length());

  max_length= adjust_max_effective_column_length(field_par, max_length);

  fixed= 1;
  if (field->table->s->tmp_table == SYSTEM_TMP_TABLE)
    any_privileges= 0;
}


uint Item::decimal_precision() const
{
  Item_result restype= result_type();

  if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT))
  {
    uint prec=
      my_decimal_length_to_precision(max_char_length(), decimals,
                                     unsigned_flag);
    return MY_MIN(prec, DECIMAL_MAX_PRECISION);
  }
  uint res= max_char_length();
  /*
    Return at least one decimal digit, even if Item::max_char_length()
    returned  0. This is important to avoid attempts to create fields of types
    INT(0) or DECIMAL(0,0) when converting NULL or empty strings to INT/DECIMAL:
      CREATE TABLE t1 AS SELECT CONVERT(NULL,SIGNED) AS a;
  */
  return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1;
}


bool Item_default_value::fix_fields(THD *thd, Item **items)
{
  Item *real_arg;
  Item_field *field_arg;
  Field *def_field;
  DBUG_ASSERT(fixed == 0);

  if (!arg)
  {
    fixed= 1;
    return FALSE;
  }

  /*
    DEFAULT() do not need table field so should not ask handler to bring
    field value (mark column for read)
  */
  enum_mark_columns save_mark_used_columns= thd->mark_used_columns;
  thd->mark_used_columns= MARK_COLUMNS_NONE;
  if (!arg->fixed && arg->fix_fields(thd, &arg))
  {
    thd->mark_used_columns= save_mark_used_columns;
    goto error;
  }
  thd->mark_used_columns= save_mark_used_columns;

  real_arg= arg->real_item();
  if (real_arg->type() != FIELD_ITEM)
  {
    my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name);
    goto error;
  }

  field_arg= (Item_field *)real_arg;
  if ((field_arg->field->flags & NO_DEFAULT_VALUE_FLAG))
  {
    my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), field_arg->field->field_name);
    goto error;
  }
  if (!(def_field= (Field*) thd->alloc(field_arg->field->size_of())))
    goto error;
  cached_field= def_field;
  memcpy((void *)def_field, (void *)field_arg->field,
         field_arg->field->size_of());
  def_field->reset_fields();
  // If non-constant default value expression
  if (def_field->default_value && def_field->default_value->flags)
  {
    uchar *newptr= (uchar*) thd->alloc(1+def_field->pack_length());
    if (!newptr)
      goto error;
    /*
      Even if DEFAULT() do not read tables fields, the default value
      expression can do it.
    */
    fix_session_vcol_expr_for_read(thd, def_field, def_field->default_value);
    if (thd->mark_used_columns != MARK_COLUMNS_NONE)
      def_field->default_value->expr->update_used_tables();
    def_field->move_field(newptr+1, def_field->maybe_null() ? newptr : 0, 1);
  }
  else
    def_field->move_field_offset((my_ptrdiff_t)
                                 (def_field->table->s->default_values -
                                  def_field->table->record[0]));
  set_field(def_field);
  return FALSE;

error:
  context->process_error(thd);
  return TRUE;
}


void Item_param::set_double(double d)
{
  DBUG_ENTER("Item_param::set_double");
  value.real= d;
  state= REAL_VALUE;
  collation.set_numeric();
  max_length= DBL_DIG + 8;
  decimals= NOT_FIXED_DEC;
  maybe_null= 0;
  null_value= 0;
  fix_type(Item::REAL_ITEM);
  DBUG_VOID_RETURN;
}


Item_param::eq(const Item *item, bool binary_cmp) const
{
  if (!basic_const_item())
    return FALSE;

  // There's no "default". See comments in Item_param::save_in_field().
  switch (state) {
  case IGNORE_VALUE:
  case DEFAULT_VALUE:
    invalid_default_param();
    return false;
  case NULL_VALUE:
    return null_eq(item);
  case INT_VALUE:
    return int_eq(value.integer, item);
  case REAL_VALUE:
    return real_eq(value.real, item);
  case STRING_VALUE:
  case LONG_DATA_VALUE:
    return str_eq(&str_value, item, binary_cmp);
  case DECIMAL_VALUE:
  case TIME_VALUE:
  case NO_VALUE:
    return false;
  }
  DBUG_ASSERT(0); // Garbage
  return FALSE;
}


longlong Item_func_between::val_int_cmp_string()
{
  String *value,*a,*b;
  value=args[0]->val_str(&value0);
  if ((null_value=args[0]->null_value))
    return 0;
  a= args[1]->val_str(&value1);
  b= args[2]->val_str(&value2);
  if (!args[1]->null_value && !args[2]->null_value)
    return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 &&
                        sortcmp(value,b,cmp_collation.collation) <= 0) !=
                       negated);
  if (args[1]->null_value && args[2]->null_value)
    null_value= true;
  else if (args[1]->null_value)
  {
    // Set to not null if false range.
    null_value= sortcmp(value,b,cmp_collation.collation) <= 0;
  }
  else
  {
    // Set to not null if false range.
    null_value= sortcmp(value,a,cmp_collation.collation) >= 0;
  }
  return (longlong) (!null_value && negated);
}


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


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


  inline void append(const char *str, uint length)
  {
    str_value.append(str, length);
    max_length= str_value.numchars() * collation.collation->mbmaxlen;
  }


double val_real() { return decimal_value.to_double(); }


bool Item_func_in::fix_for_scalar_comparison_using_cmp_items(THD *thd,
                                                             uint found_types)
{
  if (found_types & (1U << STRING_RESULT) &&
      agg_arg_charsets_for_comparison(cmp_collation, args, arg_count))
    return true;
  if (make_unique_cmp_items(thd, cmp_collation.collation))
    return true;
  return false;
}


int cmp_item_temporal::compare(cmp_item *ci)
{
  cmp_item_temporal *l_cmp= (cmp_item_temporal *)ci;
  return (value < l_cmp->value) ? -1 : ((value == l_cmp->value) ? 0 : 1);
}


bool is_bool_literal() const { return true; }


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


  double val_real()
  {
    return to_datetime(current_thd).to_double();
  }


Item* Item_func_case_simple::propagate_equal_fields(THD *thd,
                                                    const Context &ctx,
                                                    COND_EQUAL *cond)
{
  const Type_handler *first_expr_cmp_handler;

  first_expr_cmp_handler= args[0]->type_handler_for_comparison();
  /*
    Cannot replace the CASE (the switch) argument if
    there are multiple comparison types were found, or found a single
    comparison type that is not equal to args[0]->cmp_type().

    - Example: multiple comparison types, can't propagate:
        WHERE CASE str_column
              WHEN 'string' THEN TRUE
              WHEN 1 THEN TRUE
              ELSE FALSE END;

    - Example: a single incompatible comparison type, can't propagate:
        WHERE CASE str_column
              WHEN DATE'2001-01-01' THEN TRUE
              ELSE FALSE END;

    - Example: a single incompatible comparison type, can't propagate:
        WHERE CASE str_column
              WHEN 1 THEN TRUE
              ELSE FALSE END;

    - Example: a single compatible comparison type, ok to propagate:
        WHERE CASE str_column
              WHEN 'str1' THEN TRUE
              WHEN 'str2' THEN TRUE
              ELSE FALSE END;
  */
  if (m_found_types == (1UL << first_expr_cmp_handler->cmp_type()))
    propagate_and_change_item_tree(thd, &args[0], cond,
      Context(ANY_SUBST, first_expr_cmp_handler, cmp_collation.collation));

  /*
    These arguments are in comparison.
    Allow invariants of the same value during propagation.
    Note, as we pass ANY_SUBST, none of the WHEN arguments will be
    replaced to zero-filled constants (only IDENTITY_SUBST allows this).
    Such a change for WHEN arguments would require rebuilding cmp_items.
  */
  uint i, count= when_count();
  for (i= 1; i <= count; i++)
  {
    Type_handler_hybrid_field_type tmp(first_expr_cmp_handler);
    if (!tmp.aggregate_for_comparison(args[i]->type_handler_for_comparison()))
      propagate_and_change_item_tree(thd, &args[i], cond,
        Context(ANY_SUBST, tmp.type_handler(), cmp_collation.collation));
  }

  // THEN and ELSE arguments (they are not in comparison)
  for (; i < arg_count; i++)
    propagate_and_change_item_tree(thd, &args[i], cond, Context_identity());

  return this;
}


bool Item_func_decode_oracle::fix_length_and_dec()
{
  THD *thd= current_thd;
  return (aggregate_then_and_else_arguments(thd, when_count() + 1) ||
          aggregate_switch_and_when_arguments(thd, true));
}


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


void Item_cond_and::mark_as_condition_AND_part(TABLE_LIST *embedding)
{
  List_iterator<Item> li(list);
  Item *item;
  while ((item=li++))
  {
    item->mark_as_condition_AND_part(embedding);
  }
}


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


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

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

  return re.match() ? re.subpattern_start(0) + 1 : 0;
}


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


longlong val_int() { return has_value() ? Date(this).to_longlong() : 0; }


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


bool is_evaluable_expression() const { return false; }


  ValueBuffer()
  {
    reset_buffer();
  }


Item *Item_func_not::neg_transformer(THD *thd)	/* NOT(x)  ->  x */
{
  return args[0];
}


virtual bool with_subquery() const { DBUG_ASSERT(is_fixed()); return false; }


virtual bool is_order_clause_position() const { return false; }


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


  Tmp_field_src()
   :m_field(0),
    m_default_field(0),
    m_item_result_field(0)
  { }


  Item_date_literal_for_invalid_dates(THD *thd, const Date *ltime)
   :Item_date_literal(thd, ltime)
  {
    maybe_null= false;
  }


Item_func_nullif::is_null()
{
  return (null_value= (!compare() ? 1 : args[2]->is_null()));
}


my_decimal *Item_func_ifnull::decimal_op(my_decimal *decimal_value)
{
  DBUG_ASSERT(fixed == 1);
  my_decimal *value= args[0]->val_decimal(decimal_value);
  if (!args[0]->null_value)
  {
    null_value= 0;
    return value;
  }
  value= args[1]->val_decimal(decimal_value);
  if ((null_value= args[1]->null_value))
    return 0;
  return value;
}


void in_row::set(uint pos, Item *item)
{
  DBUG_ENTER("in_row::set");
  DBUG_PRINT("enter", ("pos: %u  item: %p", pos,item));
  ((cmp_item_row*) base)[pos].store_value_by_template(current_thd, &tmp, item);
  DBUG_VOID_RETURN;
}


Item_cache_decimal(THD *thd): Item_cache(thd, &type_handler_newdecimal) {}


uint length() const { return m_length; }


void Item_equal::print(String *str, enum_query_type query_type)
{
  if (cond_false)
  {
    str->append('0');
    return;
  }
  str->append(func_name());
  str->append('(');
  List_iterator_fast<Item> it(equal_items);
  Item *item;
  item= it++;
  item->print(str, query_type);
  while ((item= it++))
  {
    str->append(',');
    str->append(' ');
    item->print(str, query_type);
  }
  str->append(')');
}


  longlong val_int()
  {
    return longlong_from_string_with_check(&str_value);
  }


int Arg_comparator::compare_e_decimal()
{
  VDec val1(*a), val2(*b);
  if (val1.is_null() || val2.is_null())
    return MY_TEST(val1.is_null() && val2.is_null());
  val1.round_self_if_needed((*a)->decimals, HALF_UP);
  val2.round_self_if_needed((*b)->decimals, HALF_UP);
  return MY_TEST(val1.cmp(val2) == 0);
}


bool Item_bool_rowready_func2::fix_length_and_dec()
{
  max_length= 1;				     // Function returns 0 or 1

  /*
    As some compare functions are generated after sql_yacc,
    we have to check for out of memory conditions here
  */
  if (!args[0] || !args[1])
    return FALSE;
  return setup_args_and_comparator(current_thd, &cmp);
}


Item_func_ifnull::str_op(String *str)
{
  DBUG_ASSERT(fixed == 1);
  String *res  =args[0]->val_str(str);
  if (!args[0]->null_value)
  {
    null_value=0;
    res->set_charset(collation.collation);
    return res;
  }
  res=args[1]->val_str(str);
  if ((null_value=args[1]->null_value))
    return 0;
  res->set_charset(collation.collation);
  return res;
}


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


uchar *in_longlong::get_value(Item *item)
{
  tmp.val= item->val_int();
  if (item->null_value)
    return 0;
  tmp.unsigned_flag= item->unsigned_flag;
  return (uchar*) &tmp;
}


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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)
  { return get_date_from_int(thd, ltime, fuzzydate); }


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


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


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


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


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


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


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


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


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


static void plugin_vars_free_values(sys_var *vars)
{
  DBUG_ENTER("plugin_vars_free_values");

  for (sys_var *var= vars; var; var= var->next)
  {
    sys_var_pluginvar *piv= var->cast_pluginvar();
    if (piv &&
        ((piv->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR) &&
        (piv->plugin_var->flags & PLUGIN_VAR_MEMALLOC))
    {
      /* Free the string from global_system_variables. */
      char **valptr= (char**) piv->real_value_ptr(NULL, OPT_GLOBAL);
      DBUG_PRINT("plugin", ("freeing value for: '%s'  addr: %p",
                            var->name.str, valptr));
      my_free(*valptr);
      *valptr= NULL;
    }
  }
  DBUG_VOID_RETURN;
}


  uchar *default_value_ptr(THD *thd)
  { return do_value_ptr(thd, OPT_DEFAULT, 0); }


static int item_value_type(struct st_mysql_value *value)
{
  switch (((st_item_value_holder*)value)->item->result_type()) {
  case INT_RESULT:
    return MYSQL_VALUE_TYPE_INT;
  case REAL_RESULT:
    return MYSQL_VALUE_TYPE_REAL;
  default:
    return MYSQL_VALUE_TYPE_STRING;
  }
}


sys_var_pluginvar::sys_var_pluginvar(sys_var_chain *chain, const char *name_arg,
        st_plugin_int *p, st_mysql_sys_var *pv)
    : sys_var(chain, name_arg, pv->comment, pluginvar_sysvar_flags(pv),
              0, pv->flags & PLUGIN_VAR_NOCMDOPT ? -1 : 0, NO_ARG,
              pluginvar_show_type(pv), 0,
              NULL, VARIABLE_NOT_IN_BINLOG, NULL, NULL, NULL),
    plugin(p), plugin_var(pv)
{
  plugin_var->name= name_arg;
  plugin_opt_set_limits(&option, pv);
}


bool sys_var_pluginvar::session_update(THD *thd, set_var *var)
{
  DBUG_ASSERT(!is_readonly());
  DBUG_ASSERT(plugin_var->flags & PLUGIN_VAR_THDLOCAL);
  DBUG_ASSERT(thd == current_thd);

  mysql_mutex_lock(&LOCK_global_system_variables);
  void *tgt= real_value_ptr(thd, OPT_SESSION);
  const void *src= var->value ? (void*)&var->save_result
                              : (void*)real_value_ptr(thd, OPT_GLOBAL);
  mysql_mutex_unlock(&LOCK_global_system_variables);

  plugin_var->update(thd, plugin_var, tgt, src);

  return false;
}


static void init_plugin_psi_keys(void)
{
  const char* category= "sql";
  int count;

  if (PSI_server == NULL)
    return;

  count= array_elements(all_plugin_mutexes);
  PSI_server->register_mutex(category, all_plugin_mutexes, count);
}


JOIN::reinit()
{
  DBUG_ENTER("JOIN::reinit");

  unit->offset_limit_cnt= (ha_rows)(select_lex->offset_limit ?
                                    select_lex->offset_limit->val_uint() : 0);

  first_record= false;
  group_sent= false;
  cleaned= false;

  if (aggr_tables)
  {
    JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt();
    JOIN_TAB *end_tab= curr_tab + aggr_tables;
    for ( ; curr_tab < end_tab; curr_tab++)
    {
      TABLE *tmp_table= curr_tab->table;
      if (!tmp_table->is_created())
        continue;
      tmp_table->file->extra(HA_EXTRA_RESET_STATE);
      tmp_table->file->ha_delete_all_rows();
    }
  }
  clear_sj_tmp_tables(this);
  if (current_ref_ptrs != items0)
  {
    set_items_ref_array(items0);
    set_group_rpa= false;
  }

  /* need to reset ref access state (see join_read_key) */
  if (join_tab)
  {
    JOIN_TAB *tab;
    for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITH_CONST_TABLES); tab;
         tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS))
    {
      tab->ref.key_err= TRUE;
    }
  }

  /* Reset of sum functions */
  if (sum_funcs)
  {
    Item_sum *func, **func_ptr= sum_funcs;
    while ((func= *(func_ptr++)))
      func->clear();
  }

  if (no_rows_in_result_called)
  {
    /* Reset effect of possible no_rows_in_result() */
    List_iterator_fast<Item> it(fields_list);
    Item *item;
    no_rows_in_result_called= 0;
    while ((item= it++))
      item->restore_to_before_no_rows_in_result();
  }

  if (!(select_options & SELECT_DESCRIBE))
    init_ftfuncs(thd, select_lex, MY_TEST(order));

  DBUG_RETURN(0);
}


Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value,
                                  bool top_level_arg)
{
  Item *real_item= args[0]->real_item();
  if (real_item->type() == Item::FIELD_ITEM)
  {
    Field *field= ((Item_field*) real_item)->field;

    if (((field->type() == MYSQL_TYPE_DATE) ||
         (field->type() == MYSQL_TYPE_DATETIME)) &&
         (field->flags & NOT_NULL_FLAG))
    {
      /* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */
      /*
        See BUG#12594011
        Documentation says that
        SELECT datetime_notnull d FROM t1 WHERE d IS NULL
        shall return rows where d=='0000-00-00'

        Thus, for DATE and DATETIME columns defined as NOT NULL,
        "date_notnull IS NULL" has to be modified to
        "date_notnull IS NULL OR date_notnull == 0" (if outer join)
        "date_notnull == 0"                         (otherwise)

      */

      Item *item0= new(thd->mem_root) Item_int(thd, (longlong) 0, 1);
      Item *eq_cond= new(thd->mem_root) Item_func_eq(thd, args[0], item0);
      if (!eq_cond)
        return this;

      COND *cond= this;
      if (field->table->pos_in_table_list->is_inner_table_of_outer_join())
      {
        // outer join: transform "col IS NULL" to "col IS NULL or col=0"
        Item *or_cond= new(thd->mem_root) Item_cond_or(thd, eq_cond, this);
        if (!or_cond)
          return this;
        cond= or_cond;
      }
      else
      {
        // not outer join: transform "col IS NULL" to "col=0"
        cond= eq_cond;
      }

      cond->fix_fields(thd, &cond);
      /*
        Note: although args[0] is a field, cond can still be a constant
        (in case field is a part of a dependent subquery).

        Note: we call cond->Item::remove_eq_conds() non-virtually (statically)
        for performance purpose.
        A non-qualified call, i.e. just cond->remove_eq_conds(),
        would call Item_bool_func2::remove_eq_conds() instead, which would
        try to do some extra job to detect if args[0] and args[1] are
        equivalent items. We know they are not (we have field=0 here).
      */
      return cond->Item::remove_eq_conds(thd, cond_value, false);
    }

    /*
      Handles this special case for some ODBC applications:
      The are requesting the row that was just updated with a auto_increment
      value with this construct:

      SELECT * from table_name where auto_increment_column IS NULL
      This will be changed to:
      SELECT * from table_name where auto_increment_column = LAST_INSERT_ID

      Note, this substitution is done if the NULL test is the only condition!
      If the NULL test is a part of a more complex condition, it is not
      substituted and is treated normally:
        WHERE auto_increment IS NULL AND something_else
    */

    if (top_level_arg) // "auto_increment_column IS NULL" is the only condition
    {
      if (field->flags & AUTO_INCREMENT_FLAG && !field->table->maybe_null &&
          (thd->variables.option_bits & OPTION_AUTO_IS_NULL) &&
          (thd->first_successful_insert_id_in_prev_stmt > 0 &&
           thd->substitute_null_with_insert_id))
      {
  #ifdef HAVE_QUERY_CACHE
        query_cache_abort(thd, &thd->query_cache_tls);
  #endif
        COND *new_cond, *cond= this;
        if ((new_cond= new (thd->mem_root) Item_func_eq(thd, args[0],
                                        new (thd->mem_root) Item_int(thd, "last_insert_id()",
                                                     thd->read_first_successful_insert_id_in_prev_stmt(),
                                                     MY_INT64_NUM_DECIMAL_DIGITS))))
        {
          cond= new_cond;
          /*
            Item_func_eq can't be fixed after creation so we do not check
            cond->fixed, also it do not need tables so we use 0 as second
            argument.
          */
          cond->fix_fields(thd, &cond);
        }
        /*
          IS NULL should be mapped to LAST_INSERT_ID only for first row, so
          clear for next row
        */
        thd->substitute_null_with_insert_id= FALSE;

        *cond_value= Item::COND_OK;
        return cond;
      }
    }
  }
  return Item::remove_eq_conds(thd, cond_value, top_level_arg);
}


static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
                               KEYUSE *org_keyuse, bool allow_full_scan,
                               table_map used_tables)
{
  uint keyparts, length, key;
  TABLE *table;
  KEY *keyinfo;
  KEYUSE *keyuse= org_keyuse;
  bool ftkey= (keyuse->keypart == FT_KEYPART);
  THD *thd= join->thd;
  DBUG_ENTER("create_ref_for_key");

  /*  Use best key from find_best */
  table= j->table;
  key= keyuse->key;
  if (!is_hash_join_key_no(key))
    keyinfo= table->key_info+key;
  else
  {
    if (create_hj_key_for_table(join, j, org_keyuse, used_tables))
      DBUG_RETURN(TRUE);
    keyinfo= j->hj_key;
  }

  if (ftkey)
  {
    Item_func_match *ifm=(Item_func_match *)keyuse->val;

    length=0;
    keyparts=1;
    ifm->join_key=1;
  }
  else
  {
    keyparts=length=0;
    uint found_part_ref_or_null= 0;
    /*
      Calculate length for the used key
      Stop if there is a missing key part or when we find second key_part
      with KEY_OPTIMIZE_REF_OR_NULL
    */
    do
    {
      if (!(~used_tables & keyuse->used_tables) &&
	  j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse))
      {
        if  (are_tables_local(j, keyuse->val->used_tables()))
        {
          if ((is_hash_join_key_no(key) && keyuse->keypart != NO_KEYPART) ||
              (!is_hash_join_key_no(key) && keyparts == keyuse->keypart &&
               !(found_part_ref_or_null & keyuse->optimize)))
          {
             length+= keyinfo->key_part[keyparts].store_length;
             keyparts++;
             found_part_ref_or_null|= keyuse->optimize & ~KEY_OPTIMIZE_EQ;
          }
        }
      }
      keyuse++;
    } while (keyuse->table == table && keyuse->key == key);

    if (!keyparts && allow_full_scan)
    {
      /* It's a LooseIndexScan strategy scanning whole index */
      j->type= JT_ALL;
      j->index= key;
      DBUG_RETURN(FALSE);
    }

    DBUG_ASSERT(length > 0);
    DBUG_ASSERT(keyparts != 0);
  } /* not ftkey */

  /* set up fieldref */
  j->ref.key_parts= keyparts;
  j->ref.key_length= length;
  j->ref.key= (int) key;
  if (!(j->ref.key_buff= (uchar*) thd->calloc(ALIGN_SIZE(length)*2)) ||
      !(j->ref.key_copy= (store_key**) thd->alloc((sizeof(store_key*) *
						          (keyparts+1)))) ||
      !(j->ref.items=(Item**) thd->alloc(sizeof(Item*)*keyparts)) ||
      !(j->ref.cond_guards= (bool**) thd->alloc(sizeof(uint*)*keyparts)))
  {
    DBUG_RETURN(TRUE);
  }
  j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length);
  j->ref.key_err=1;
  j->ref.has_record= FALSE;
  j->ref.null_rejecting= 0;
  j->ref.disable_cache= FALSE;
  j->ref.null_ref_part= NO_REF_PART;
  j->ref.const_ref_part_map= 0;
  keyuse=org_keyuse;

  store_key **ref_key= j->ref.key_copy;
  uchar *key_buff=j->ref.key_buff, *null_ref_key= 0;
  uint null_ref_part= NO_REF_PART;
  bool keyuse_uses_no_tables= TRUE;
  if (ftkey)
  {
    j->ref.items[0]=((Item_func*)(keyuse->val))->key_item();
    /* Predicates pushed down into subquery can't be used FT access */
    j->ref.cond_guards[0]= NULL;
    if (keyuse->used_tables)
      DBUG_RETURN(TRUE);                        // not supported yet. SerG

    j->type=JT_FT;
  }
  else
  {
    uint i;
    for (i=0 ; i < keyparts ; keyuse++,i++)
    {
      while (((~used_tables) & keyuse->used_tables) ||
	     !j->keyuse_is_valid_for_access_in_chosen_plan(join, keyuse) ||
             keyuse->keypart == NO_KEYPART ||
	     (keyuse->keypart !=
              (is_hash_join_key_no(key) ?
                 keyinfo->key_part[i].field->field_index : i)) ||
             !are_tables_local(j, keyuse->val->used_tables()))
	 keyuse++;                              	/* Skip other parts */

      uint maybe_null= MY_TEST(keyinfo->key_part[i].null_bit);
      j->ref.items[i]=keyuse->val;		// Save for cond removal
      j->ref.cond_guards[i]= keyuse->cond_guard;
      if (keyuse->null_rejecting)
        j->ref.null_rejecting|= (key_part_map)1 << i;
      keyuse_uses_no_tables= keyuse_uses_no_tables && !keyuse->used_tables;
      /*
        Todo: we should remove this check for thd->lex->describe on the next
        line. With SHOW EXPLAIN code, EXPLAIN printout code no longer depends
        on it. However, removing the check caused change in lots of query
        plans! Does the optimizer depend on the contents of
        table_ref->key_copy ? If yes, do we produce incorrect EXPLAINs?
      */
      if (!keyuse->val->used_tables() && !thd->lex->describe)
      {					// Compare against constant
	store_key_item tmp(thd,
                           keyinfo->key_part[i].field,
                           key_buff + maybe_null,
                           maybe_null ?  key_buff : 0,
                           keyinfo->key_part[i].length,
                           keyuse->val,
                           FALSE);
	if (thd->is_fatal_error)
	  DBUG_RETURN(TRUE);
	tmp.copy();
        j->ref.const_ref_part_map |= key_part_map(1) << i ;
      }
      else
	*ref_key++= get_store_key(thd,
				  keyuse,join->const_table_map,
				  &keyinfo->key_part[i],
				  key_buff, maybe_null);
      /*
	Remember if we are going to use REF_OR_NULL
	But only if field _really_ can be null i.e. we force JT_REF
	instead of JT_REF_OR_NULL in case if field can't be null
      */
      if ((keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL) && maybe_null)
      {
	null_ref_key= key_buff;
        null_ref_part= i;
      }
      key_buff+= keyinfo->key_part[i].store_length;
    }
  } /* not ftkey */
  *ref_key=0;				// end_marker
  if (j->type == JT_FT)
    DBUG_RETURN(0);
  ulong key_flags= j->table->actual_key_flags(keyinfo);
  if (j->type == JT_CONST)
    j->table->const_table= 1;
  else if (!((keyparts == keyinfo->user_defined_key_parts &&
              ((key_flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)) ||
	     (keyparts > keyinfo->user_defined_key_parts &&   // true only for extended keys
              MY_TEST(key_flags & HA_EXT_NOSAME) &&
              keyparts == keyinfo->ext_key_parts)) ||
	    null_ref_key)
  {
    /* Must read with repeat */
    j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
    j->ref.null_ref_key= null_ref_key;
    j->ref.null_ref_part= null_ref_part;
  }
  else if (keyuse_uses_no_tables)
  {
    /*
      This happen if we are using a constant expression in the ON part
      of an LEFT JOIN.
      SELECT * FROM a LEFT JOIN b ON b.key=30
      Here we should not mark the table as a 'const' as a field may
      have a 'normal' value or a NULL value.
    */
    j->type=JT_CONST;
  }
  else
    j->type=JT_EQ_REF;

  j->read_record.unlock_row= (j->type == JT_EQ_REF)?
                             join_read_key_unlock_row : rr_unlock_row;
  DBUG_RETURN(0);
}


int join_init_read_record(JOIN_TAB *tab)
{
  /*
    Note: the query plan tree for the below operations is constructed in
    save_agg_explain_data.
  */
  if (tab->distinct && tab->remove_duplicates())  // Remove duplicates.
    return 1;
  if (tab->filesort && tab->sort_table())     // Sort table.
    return 1;

  DBUG_EXECUTE_IF("kill_join_init_read_record",
                  tab->join->thd->set_killed(KILL_QUERY););
  if (tab->select && tab->select->quick && tab->select->quick->reset())
  {
    /* Ensures error status is propagated back to client */
    report_error(tab->table,
                 tab->join->thd->killed ? HA_ERR_QUERY_INTERRUPTED : HA_ERR_OUT_OF_MEM);
    return 1;
  }
  /* make sure we won't get ER_QUERY_INTERRUPTED from any code below */
  DBUG_EXECUTE_IF("kill_join_init_read_record",
                  tab->join->thd->reset_killed(););
  if (!tab->preread_init_done  && tab->preread_init())
    return 1;
  if (init_read_record(&tab->read_record, tab->join->thd, tab->table,
                       tab->select, tab->filesort_result, 1,1, FALSE))
    return 1;
  return (*tab->read_record.read_record)(&tab->read_record);
}