/*
   Copyright (c) 2015, 2020, MariaDB

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; version 2 of the License.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */

#include "mariadb.h"
#include "sql_type.h"
#include "sql_type_geom.h"
#include "sql_const.h"
#include "sql_class.h"
#include "sql_time.h"
#include "item.h"
#include "log.h"
#include "tztime.h"
#include <mysql/plugin_data_type.h>


const DTCollation &DTCollation_numeric::singleton()
{
  static const DTCollation_numeric tmp;
  return tmp;
}

Named_type_handler<Type_handler_row> type_handler_row("row");

Named_type_handler<Type_handler_null> type_handler_null("null");

Named_type_handler<Type_handler_bool> type_handler_bool("boolean");
Named_type_handler<Type_handler_tiny> type_handler_stiny("tinyint");
Named_type_handler<Type_handler_short> type_handler_sshort("smallint");
Named_type_handler<Type_handler_long> type_handler_slong("int");
Named_type_handler<Type_handler_int24> type_handler_sint24("mediumint");
Named_type_handler<Type_handler_longlong> type_handler_slonglong("bigint");
Named_type_handler<Type_handler_utiny> type_handler_utiny("tiny unsigned");
Named_type_handler<Type_handler_ushort> type_handler_ushort("smallint unsigned");
Named_type_handler<Type_handler_ulong> type_handler_ulong("int unsigned");
Named_type_handler<Type_handler_uint24> type_handler_uint24("mediumint unsigned");
Named_type_handler<Type_handler_ulonglong> type_handler_ulonglong("bigint unsigned");
Named_type_handler<Type_handler_vers_trx_id> type_handler_vers_trx_id("bigint unsigned");
Named_type_handler<Type_handler_float> type_handler_float("float");
Named_type_handler<Type_handler_double> type_handler_double("double");
Named_type_handler<Type_handler_bit> type_handler_bit("bit");

Named_type_handler<Type_handler_olddecimal> type_handler_olddecimal("decimal");
Named_type_handler<Type_handler_newdecimal> type_handler_newdecimal("decimal");

Named_type_handler<Type_handler_year> type_handler_year("year");
Named_type_handler<Type_handler_year> type_handler_year2("year");
Named_type_handler<Type_handler_time> type_handler_time("time");
Named_type_handler<Type_handler_date> type_handler_date("date");
Named_type_handler<Type_handler_timestamp> type_handler_timestamp("timestamp");
Named_type_handler<Type_handler_timestamp2> type_handler_timestamp2("timestamp");
Named_type_handler<Type_handler_datetime> type_handler_datetime("datetime");
Named_type_handler<Type_handler_time2> type_handler_time2("time");
Named_type_handler<Type_handler_newdate> type_handler_newdate("date");
Named_type_handler<Type_handler_datetime2> type_handler_datetime2("datetime");

Named_type_handler<Type_handler_enum> type_handler_enum("enum");
Named_type_handler<Type_handler_set> type_handler_set("set");

Named_type_handler<Type_handler_string> type_handler_string("char");
Named_type_handler<Type_handler_var_string> type_handler_var_string("varchar");
Named_type_handler<Type_handler_varchar> type_handler_varchar("varchar");
Named_type_handler<Type_handler_hex_hybrid> type_handler_hex_hybrid("hex_hybrid");
Named_type_handler<Type_handler_varchar_compressed> type_handler_varchar_compressed("varchar");

Named_type_handler<Type_handler_tiny_blob> type_handler_tiny_blob("tinyblob");
Named_type_handler<Type_handler_medium_blob> type_handler_medium_blob("mediumblob");
Named_type_handler<Type_handler_long_blob> type_handler_long_blob("longblob");
Named_type_handler<Type_handler_blob> type_handler_blob("blob");
Named_type_handler<Type_handler_blob_compressed> type_handler_blob_compressed("blob");

Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff;

Vers_type_timestamp       vers_type_timestamp;
Vers_type_trx             vers_type_trx;

/***************************************************************************/



class Type_collection_std: public Type_collection
{
public:
  const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
  {
    return NULL;
  }
  const Type_handler *aggregate_for_result(const Type_handler *a,
                                           const Type_handler *b)
                                           const override
  {
    return Type_handler::aggregate_for_result_traditional(a, b);
  }
  const Type_handler *aggregate_for_comparison(const Type_handler *a,
                                               const Type_handler *b)
                                               const override;
  const Type_handler *aggregate_for_min_max(const Type_handler *a,
                                            const Type_handler *b)
                                            const override;
  const Type_handler *aggregate_for_num_op(const Type_handler *a,
                                           const Type_handler *b)
                                           const override;
};


static Type_collection_std type_collection_std;

const Type_collection *Type_handler::type_collection() const
{
  return &type_collection_std;
}


bool Type_handler::is_traditional_scalar_type() const
{
  return type_collection() == &type_collection_std;
}


class Type_collection_row: public Type_collection
{
public:
  bool init(Type_handler_data *data) override
  {
    return false;
  }
  const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
  {
    return NULL;
  }
  const Type_handler *aggregate_for_result(const Type_handler *a,
                                           const Type_handler *b)
                                           const override
  {
    return NULL;
  }
  const Type_handler *aggregate_for_comparison(const Type_handler *a,
                                               const Type_handler *b)
                                               const override
  {
    DBUG_ASSERT(a == &type_handler_row);
    DBUG_ASSERT(b == &type_handler_row);
    return &type_handler_row;
  }
  const Type_handler *aggregate_for_min_max(const Type_handler *a,
                                            const Type_handler *b)
                                            const override
  {
    return NULL;
  }
  const Type_handler *aggregate_for_num_op(const Type_handler *a,
                                           const Type_handler *b)
                                           const override
  {
    return NULL;
  }
};


static Type_collection_row type_collection_row;

const Type_collection *Type_handler_row::type_collection() const
{
  return &type_collection_row;
}


bool Type_handler_data::init()
{
#ifdef HAVE_SPATIAL
  return type_collection_geometry.init(this);
#endif
  return false;
}


Schema *Type_handler::schema() const
{
  return &mariadb_schema;
}


const Type_handler *
Type_handler::handler_by_name(THD *thd, const LEX_CSTRING &name)
{
  plugin_ref plugin;
  if ((plugin= my_plugin_lock_by_name(thd, &name, MariaDB_DATA_TYPE_PLUGIN)))
  {
    /*
      Data type plugins do not maintain ref_count yet.
      For now we have only mandatory built-in plugins
      and dynamic plugins for test purposes.
      It should be safe to unlock the plugin immediately.
    */
    const Type_handler *ph= reinterpret_cast<st_mariadb_data_type*>
                              (plugin_decl(plugin)->info)->type_handler;
    plugin_unlock(thd, plugin);
    return ph;
  }

#ifdef HAVE_SPATIAL
  const Type_handler *ha= type_collection_geometry.handler_by_name(name);
  if (ha)
    return ha;
#endif
  return NULL;
}


#ifndef DBUG_OFF
static const Type_handler *frm_data_type_info_emulate(const LEX_CSTRING &name)
{
  if (Name(STRING_WITH_LEN("xchar")).eq(name))
    return &type_handler_string;
  if (Name(STRING_WITH_LEN("xblob")).eq(name))
     return &type_handler_blob;
  return NULL;
}
#endif


const Type_handler *
Type_handler::handler_by_name_or_error(THD *thd, const LEX_CSTRING &name)
{
  const Type_handler *h= handler_by_name(thd, name);
  DBUG_EXECUTE_IF("emulate_handler_by_name_or_error_failure", h= NULL;);
  if (!h)
  {
    DBUG_EXECUTE_IF("frm_data_type_info_emulate",
      if ((h= frm_data_type_info_emulate(name)))
        return h;
    );
    my_error(ER_UNKNOWN_DATA_TYPE, MYF(0),
             ErrConvString(name.str, name.length, system_charset_info).ptr());
  }
  return h;
}


Type_handler_data *type_handler_data= NULL;


bool Float::to_string(String *val_buffer, uint dec) const
{
  uint to_length= 70;
  if (val_buffer->alloc(to_length))
    return true;

  char *to=(char*) val_buffer->ptr();
  size_t len;

  if (dec >= FLOATING_POINT_DECIMALS)
    len= my_gcvt(m_value, MY_GCVT_ARG_FLOAT, to_length - 1, to, NULL);
  else
  {
    /*
      We are safe here because the buffer length is 70, and
      fabs(float) < 10^39, dec < FLOATING_POINT_DECIMALS. So the resulting string
      will be not longer than 69 chars + terminating '\0'.
    */
    len= my_fcvt(m_value, (int) dec, to, NULL);
  }
  val_buffer->length((uint) len);
  val_buffer->set_charset(&my_charset_numeric);
  return false;
}


String_ptr::String_ptr(Item *item, String *buffer)
 :m_string_ptr(item->val_str(buffer))
{ }


Ascii_ptr::Ascii_ptr(Item *item, String *buffer)
 :String_ptr(item->val_str_ascii(buffer))
{ }


void VDec::set(Item *item)
{
  m_ptr= item->val_decimal(&m_buffer);
  DBUG_ASSERT((m_ptr == NULL) == item->null_value);
}


VDec::VDec(Item *item)
{
  m_ptr= item->val_decimal(&m_buffer);
  DBUG_ASSERT((m_ptr == NULL) == item->null_value);
}


VDec_op::VDec_op(Item_func_hybrid_field_type *item)
{
  m_ptr= item->decimal_op(&m_buffer);
  DBUG_ASSERT((m_ptr == NULL) == item->null_value);
}


date_conv_mode_t Temporal::sql_mode_for_dates(THD *thd)
{
  return ::sql_mode_for_dates(thd);
}


time_round_mode_t Temporal::default_round_mode(THD *thd)
{
  return thd->temporal_round_mode();
}


time_round_mode_t Timestamp::default_round_mode(THD *thd)
{
  return thd->temporal_round_mode();
}


my_decimal *Temporal::to_decimal(my_decimal *to) const
{
  return date2my_decimal(this, to);
}


my_decimal *Temporal::bad_to_decimal(my_decimal *to) const
{
  my_decimal_set_zero(to);
  return NULL;
}


void Temporal::make_from_str(THD *thd, Warn *warn,
                                   const char *str, size_t length,
                                   CHARSET_INFO *cs, date_mode_t fuzzydate)
{
  DBUG_EXECUTE_IF("str_to_datetime_warn",
                  push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
                               ER_YES, ErrConvString(str, length,cs).ptr()););

  if (str_to_temporal(thd, warn, str, length, cs, fuzzydate))
    make_fuzzy_date(&warn->warnings, date_conv_mode_t(fuzzydate));
  if (warn->warnings)
    warn->set_str(str, length, &my_charset_bin);
}


Temporal_hybrid::Temporal_hybrid(THD *thd, Item *item, date_mode_t fuzzydate)
{
  if (item->get_date(thd, this, fuzzydate))
    time_type= MYSQL_TIMESTAMP_NONE;
}


uint Timestamp::binary_length_to_precision(uint length)
{
  switch (length) {
  case 4: return 0;
  case 5: return 2;
  case 6: return 4;
  case 7: return 6;
  }
  DBUG_ASSERT(0);
  return 0;
}


Timestamp::Timestamp(const Native &native)
{
  DBUG_ASSERT(native.length() >= 4 && native.length() <= 7);
  uint dec= binary_length_to_precision(native.length());
  my_timestamp_from_binary(this, (const uchar *) native.ptr(), dec);
}


bool Timestamp::to_native(Native *to, uint decimals) const
{
  uint len= my_timestamp_binary_length(decimals);
  if (to->reserve(len))
    return true;
  my_timestamp_to_binary(this, (uchar *) to->ptr(), decimals);
  to->length(len);
  return false;
}


bool Timestamp::to_TIME(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) const
{
  return thd->timestamp_to_TIME(to, tv_sec, tv_usec, fuzzydate);
}


Timestamp::Timestamp(THD *thd, const MYSQL_TIME *ltime, uint *error_code)
 :Timeval(TIME_to_timestamp(thd, ltime, error_code), ltime->second_part)
{ }


Timestamp_or_zero_datetime::Timestamp_or_zero_datetime(THD *thd,
                                                       const MYSQL_TIME *ltime,
                                                       uint *error_code)
 :Timestamp(thd, ltime, error_code),
  m_is_zero_datetime(*error_code == ER_WARN_DATA_OUT_OF_RANGE)
{
  if (m_is_zero_datetime)
  {
    if (!non_zero_date(ltime))
      *error_code= 0;  // ltime was '0000-00-00 00:00:00'
  }
  else if (*error_code == ER_WARN_INVALID_TIMESTAMP)
    *error_code= 0; // ltime fell into spring time gap, adjusted.
}


bool Timestamp_or_zero_datetime::to_TIME(THD *thd, MYSQL_TIME *to,
                                         date_mode_t fuzzydate) const
{
  if (m_is_zero_datetime)
  {
    set_zero_time(to, MYSQL_TIMESTAMP_DATETIME);
    return false;
  }
  return Timestamp::to_TIME(thd, to, fuzzydate);
}


bool Timestamp_or_zero_datetime::to_native(Native *to, uint decimals) const
{
  if (m_is_zero_datetime)
  {
    to->length(0);
    return false;
  }
  return Timestamp::to_native(to, decimals);
}


int Timestamp_or_zero_datetime_native::save_in_field(Field *field,
                                                     uint decimals) const
{
  field->set_notnull();
  if (field->type_handler()->type_handler_for_native_format() ==
      &type_handler_timestamp2)
    return field->store_native(*this);
  if (is_zero_datetime())
  {
    static Datetime zero(Datetime::zero());
    return field->store_time_dec(zero.get_mysql_time(), decimals);
  }
  return field->store_timestamp_dec(Timestamp(*this).tv(), decimals);
}


void Sec6::make_from_decimal(const my_decimal *d, ulong *nanoseconds)
{
  m_neg= my_decimal2seconds(d, &m_sec, &m_usec, nanoseconds);
  m_truncated= (m_sec >= LONGLONG_MAX);
}


void Sec6::make_from_double(double nr, ulong *nanoseconds)
{
  if ((m_neg= nr < 0))
    nr= -nr;
  if ((m_truncated= nr > (double) LONGLONG_MAX))
  {
    m_sec= LONGLONG_MAX;
    m_usec= 0;
    *nanoseconds= 0;
  }
  else
  {
    m_sec= (ulonglong) nr;
    m_usec= (ulong) ((nr - floor(nr)) * 1000000000);
    *nanoseconds= m_usec % 1000;
    m_usec/= 1000;
  }
}


void Sec6::make_truncated_warning(THD *thd, const char *type_str) const
{
  char buff[1 + MAX_BIGINT_WIDTH + 1 + 6 + 1]; // '-' int '.' frac '\0'
  to_string(buff, sizeof(buff));
  thd->push_warning_truncated_wrong_value(type_str, buff);
}


bool Sec6::convert_to_mysql_time(THD *thd, int *warn, MYSQL_TIME *ltime,
                                 date_mode_t fuzzydate) const
{
  bool rc= fuzzydate & (TIME_INTERVAL_hhmmssff | TIME_INTERVAL_DAY) ?
             to_datetime_or_to_interval_hhmmssff(ltime, warn) :
           fuzzydate & TIME_TIME_ONLY ?
             to_datetime_or_time(ltime, warn, date_conv_mode_t(fuzzydate)) :
             to_datetime_or_date(ltime, warn, date_conv_mode_t(fuzzydate));
  DBUG_ASSERT(*warn || !rc);
  if (truncated())
    *warn|= MYSQL_TIME_WARN_TRUNCATED;
  return rc;
}


void Temporal::push_conversion_warnings(THD *thd, bool totally_useless_value,
                                        int warn,
                                        const char *typestr,
                                        const char *db_name,
                                        const char *table_name,
                                        const char *field_name,
                                        const char *value)
{
  if (MYSQL_TIME_WARN_HAVE_WARNINGS(warn))
    thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_WARN,
                                               totally_useless_value,
                                               typestr, value,
                                               db_name, table_name,
                                               field_name);
  else if (MYSQL_TIME_WARN_HAVE_NOTES(warn))
    thd->push_warning_wrong_or_truncated_value(Sql_condition::WARN_LEVEL_NOTE,
                                               false, typestr, value,
                                               db_name, table_name,
                                               field_name);
}


VSec9::VSec9(THD *thd, Item *item, const char *type_str, ulonglong limit)
{
  if (item->decimals == 0)
  { // optimize for an important special case
    Longlong_hybrid nr(item->val_int(), item->unsigned_flag);
    make_from_int(nr);
    m_is_null= item->null_value;
    if (!m_is_null && m_sec > limit)
    {
      m_sec= limit;
      m_truncated= true;
      ErrConvInteger err(nr);
      thd->push_warning_truncated_wrong_value(type_str, err.ptr());
    }
  }
  else if (item->cmp_type() == REAL_RESULT)
  {
    double nr= item->val_real();
    make_from_double(nr, &m_nsec);
    m_is_null= item->null_value;
    if (!m_is_null && m_sec > limit)
    {
      m_sec= limit;
      m_truncated= true;
    }
    if (m_truncated)
    {
      ErrConvDouble err(nr);
      thd->push_warning_truncated_wrong_value(type_str, err.ptr());
    }   
  }
  else
  {
    VDec tmp(item);
    (m_is_null= tmp.is_null()) ? reset() : make_from_decimal(tmp.ptr(), &m_nsec);
    if (!m_is_null && m_sec > limit)
    {
      m_sec= limit;
      m_truncated= true;
    }
    if (m_truncated)
    {
      ErrConvDecimal err(tmp.ptr());
      thd->push_warning_truncated_wrong_value(type_str, err.ptr());
    }
  }
}


Year::Year(longlong value, bool unsigned_flag, uint length)
{
  if ((m_truncated= (value < 0))) // Negative or huge unsigned
    m_year= unsigned_flag ? 9999 : 0;
  else if (value > 9999)
  {
    m_truncated= true;
    m_year= 9999;
  }
  else if (length == 2)
  {
    m_year= value < 70 ? (uint) value + 2000 :
             value <= 1900 ? (uint) value + 1900 :
             (uint) value;
  }
  else
    m_year= (uint) value;
  DBUG_ASSERT(m_year <= 9999);
}


uint Year::year_precision(const Item *item) const
{
  return item->type_handler() == &type_handler_year2 ? 2 : 4;
}


VYear::VYear(Item *item)
 :Year_null(item->to_longlong_null(), item->unsigned_flag, year_precision(item))
{ }


VYear_op::VYear_op(Item_func_hybrid_field_type *item)
 :Year_null(item->to_longlong_null_op(), item->unsigned_flag,
            year_precision(item))
{ }


const LEX_CSTRING Interval_DDhhmmssff::m_type_name=
  {STRING_WITH_LEN("INTERVAL DAY TO SECOND")};


Interval_DDhhmmssff::Interval_DDhhmmssff(THD *thd, Status *st,
                                         bool push_warnings,
                                         Item *item, ulong max_hour,
                                         time_round_mode_t mode, uint dec)
{
  switch (item->cmp_type()) {
  case ROW_RESULT:
    DBUG_ASSERT(0);
    time_type= MYSQL_TIMESTAMP_NONE;
    break;
  case TIME_RESULT:
    {
      // Rounding mode is not important here
      if (item->get_date(thd, this, Options(TIME_TIME_ONLY, TIME_FRAC_NONE)))
        time_type= MYSQL_TIMESTAMP_NONE;
      else if (time_type != MYSQL_TIMESTAMP_TIME)
      {
        st->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
        push_warning_wrong_or_truncated_value(thd, ErrConvTime(this),
                                              st->warnings);
        time_type= MYSQL_TIMESTAMP_NONE;
      }
      break;
    }
  case INT_RESULT:
  case REAL_RESULT:
  case DECIMAL_RESULT:
  case STRING_RESULT:
    {
      StringBuffer<STRING_BUFFER_USUAL_SIZE> tmp;
      String *str= item->val_str(&tmp);
      if (!str)
        time_type= MYSQL_TIMESTAMP_NONE;
      else if (str_to_DDhhmmssff(st, str->ptr(), str->length(), str->charset(),
                                 UINT_MAX32))
      {
        if (push_warnings)
          thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
                                        m_type_name.str,
                                        ErrConvString(str).ptr());
        time_type= MYSQL_TIMESTAMP_NONE;
      }
      else
      {
        if (mode == TIME_FRAC_ROUND)
          time_round_or_set_max(dec, &st->warnings, max_hour, st->nanoseconds);
        if (hour > max_hour)
        {
          st->warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
          time_type= MYSQL_TIMESTAMP_NONE;
        }
        // Warn if hour or nanosecond truncation happened
        if (push_warnings)
          push_warning_wrong_or_truncated_value(thd, ErrConvString(str),
                                                st->warnings);
      }
    }
    break;
  }
  DBUG_ASSERT(is_valid_value_slow());
}


void
Interval_DDhhmmssff::push_warning_wrong_or_truncated_value(THD *thd,
                                                           const ErrConv &str,
                                                           int warnings)
{
  if (warnings & MYSQL_TIME_WARN_OUT_OF_RANGE)
  {
    thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
                                  m_type_name.str, str.ptr());
  }
  else if (MYSQL_TIME_WARN_HAVE_WARNINGS(warnings))
  {
    thd->push_warning_truncated_wrong_value(Sql_condition::WARN_LEVEL_WARN,
                                            m_type_name.str, str.ptr());
  }
  else if (MYSQL_TIME_WARN_HAVE_NOTES(warnings))
  {
    thd->push_warning_truncated_wrong_value(Sql_condition::WARN_LEVEL_NOTE,
                                            m_type_name.str, str.ptr());
  }
}


uint Interval_DDhhmmssff::fsp(THD *thd, Item *item)
{
  switch (item->cmp_type()) {
  case INT_RESULT:
  case TIME_RESULT:
    return item->decimals;
  case REAL_RESULT:
  case DECIMAL_RESULT:
    return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
  case ROW_RESULT:
    DBUG_ASSERT(0);
    return 0;
  case STRING_RESULT:
    break;
  }
  if (!item->const_item() || item->is_expensive())
    return TIME_SECOND_PART_DIGITS;
  Status st;
  Interval_DDhhmmssff it(thd, &st, false/*no warnings*/, item, UINT_MAX32,
                         TIME_FRAC_TRUNCATE, TIME_SECOND_PART_DIGITS);
  return it.is_valid_interval_DDhhmmssff() ? st.precision :
                                             TIME_SECOND_PART_DIGITS;
}


bool Time::to_native(Native *to, uint decimals) const
{
  if (!is_valid_time())
  {
    to->length(0);
    return true;
  }
  uint len= my_time_binary_length(decimals);
  if (to->reserve(len))
    return true;
  longlong tmp= TIME_to_longlong_time_packed(get_mysql_time());
  my_time_packed_to_binary(tmp, (uchar*) to->ptr(), decimals);
  to->length(len);
  return false;
}


void Time::make_from_item(THD *thd, int *warn, Item *item, const Options opt)
{
  *warn= 0;
  if (item->get_date(thd, this, opt))
    time_type= MYSQL_TIMESTAMP_NONE;
  else
    valid_MYSQL_TIME_to_valid_value(thd, warn, opt);
}


static uint msec_round_add[7]=
{
  500000000,
  50000000,
  5000000,
  500000,
  50000,
  5000,
  0
};


Sec9 & Sec9::round(uint dec)
{
  DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
  if (Sec6::add_nanoseconds(m_nsec + msec_round_add[dec]))
    m_sec++;
  m_nsec= 0;
  Sec6::trunc(dec);
  return *this;
}


void Timestamp::round_or_set_max(uint dec, int *warn)
{
  DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
  if (add_nanoseconds_usec(msec_round_add[dec]) &&
      tv_sec++ >= TIMESTAMP_MAX_VALUE)
  {
    tv_sec= TIMESTAMP_MAX_VALUE;
    tv_usec= TIME_MAX_SECOND_PART;
    *warn|= MYSQL_TIME_WARN_OUT_OF_RANGE;
  }
  my_timeval_trunc(this, dec);
}


bool Temporal::add_nanoseconds_with_round(THD *thd, int *warn,
                                          date_conv_mode_t mode,
                                          ulong nsec)
{
  switch (time_type) {
  case MYSQL_TIMESTAMP_TIME:
  {
    ulong max_hour= (mode & (TIME_INTERVAL_DAY | TIME_INTERVAL_hhmmssff)) ?
                    TIME_MAX_INTERVAL_HOUR : TIME_MAX_HOUR;
    time_round_or_set_max(6, warn, max_hour, nsec);
    return false;
  }
  case MYSQL_TIMESTAMP_DATETIME:
    return datetime_round_or_invalidate(thd, 6, warn, nsec);
  case MYSQL_TIMESTAMP_DATE:
    return false;
  case MYSQL_TIMESTAMP_NONE:
    return false;
  case MYSQL_TIMESTAMP_ERROR:
    break;
  }
  DBUG_ASSERT(0);
  return false;
}


void Temporal::time_round_or_set_max(uint dec, int *warn,
                                     ulong max_hour, ulong nsec)
{
  DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
  if (add_nanoseconds_mmssff(nsec) && ++hour > max_hour)
  {
    time_hhmmssff_set_max(max_hour);
    *warn|= MYSQL_TIME_WARN_OUT_OF_RANGE;
  }
  my_time_trunc(this, dec);
}


void Time::round_or_set_max(uint dec, int *warn, ulong nsec)
{
  Temporal::time_round_or_set_max(dec, warn, TIME_MAX_HOUR, nsec);
  DBUG_ASSERT(is_valid_time_slow());
}


void Time::round_or_set_max(uint dec, int *warn)
{
  round_or_set_max(dec, warn, msec_round_add[dec]);
}

/**
  Create from a DATETIME by subtracting a given number of days,
  implementing an optimized version of calc_time_diff().
*/
void Time::make_from_datetime_with_days_diff(int *warn, const MYSQL_TIME *from,
                                             long days)
{
  *warn= 0;
  DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATETIME ||
              from->time_type == MYSQL_TIMESTAMP_DATE);
  long daynr= calc_daynr(from->year, from->month, from->day);
  long daydiff= daynr - days;
  if (!daynr) // Zero date
  {
    set_zero_time(this, MYSQL_TIMESTAMP_TIME);
    neg= true;
    hour= TIME_MAX_HOUR + 1; // to report "out of range" in "warn"
  }
  else if (daydiff >=0)
  {
    neg= false;
    year= month= day= 0;
    hhmmssff_copy(from);
    hour+= daydiff * 24;
    time_type= MYSQL_TIMESTAMP_TIME;
  }
  else
  {
    longlong timediff= ((((daydiff * 24LL +
                           from->hour)   * 60LL +
                           from->minute) * 60LL +
                           from->second) * 1000000LL +
                           from->second_part);
    unpack_time(timediff, this, MYSQL_TIMESTAMP_TIME);
    if (year || month)
    {
      *warn|= MYSQL_TIME_WARN_OUT_OF_RANGE;
      year= month= day= 0;
      hour= TIME_MAX_HOUR + 1;
    }
  }
  // The above code can generate TIME values outside of the valid TIME range.
  adjust_time_range_or_invalidate(warn);
}


void Time::make_from_datetime_move_day_to_hour(int *warn,
                                               const MYSQL_TIME *from)
{
  *warn= 0;
  DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATE ||
              from->time_type == MYSQL_TIMESTAMP_DATETIME);
  time_type= MYSQL_TIMESTAMP_TIME;
  neg= false;
  year= month= day= 0;
  hhmmssff_copy(from);
  datetime_to_time_YYYYMMDD_000000DD_mix_to_hours(warn, from->year,
                                                  from->month, from->day);
  adjust_time_range_or_invalidate(warn);
}


void Time::make_from_datetime(int *warn, const MYSQL_TIME *from, long curdays)
{
  if (!curdays)
    make_from_datetime_move_day_to_hour(warn, from);
  else
    make_from_datetime_with_days_diff(warn, from, curdays);
}


void Time::make_from_time(int *warn, const MYSQL_TIME *from)
{
  DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME);
  if (from->year || from->month)
    make_from_out_of_range(warn);
  else
  {
    *warn= 0;
    DBUG_ASSERT(from->day == 0);
    *(static_cast<MYSQL_TIME*>(this))= *from;
    adjust_time_range_or_invalidate(warn);
  }
}


uint Time::binary_length_to_precision(uint length)
{
  switch (length) {
  case 3: return 0;
  case 4: return 2;
  case 5: return 4;
  case 6: return 6;
  }
  DBUG_ASSERT(0);
  return 0;
}


Time::Time(const Native &native)
{
  uint dec= binary_length_to_precision(native.length());
  longlong tmp= my_time_packed_from_binary((const uchar *) native.ptr(), dec);
  TIME_from_longlong_time_packed(this, tmp);
  DBUG_ASSERT(is_valid_time());
}


Time::Time(int *warn, const MYSQL_TIME *from, long curdays)
{
  switch (from->time_type) {
  case MYSQL_TIMESTAMP_NONE:
  case MYSQL_TIMESTAMP_ERROR:
    make_from_out_of_range(warn);
    break;
  case MYSQL_TIMESTAMP_DATE:
  case MYSQL_TIMESTAMP_DATETIME:
    make_from_datetime(warn, from, curdays);
    break;
  case MYSQL_TIMESTAMP_TIME:
    make_from_time(warn, from);
    break;
  }
  DBUG_ASSERT(is_valid_value_slow());
}


Time::Time(int *warn, bool neg, ulonglong hour, uint minute, const Sec6 &second)
{
  DBUG_ASSERT(second.sec() <= 59);
  *warn= 0;
  set_zero_time(this, MYSQL_TIMESTAMP_TIME);
  MYSQL_TIME::neg= neg;
  MYSQL_TIME::hour= hour > TIME_MAX_HOUR ? (uint) (TIME_MAX_HOUR + 1) :
                                           (uint) hour;
  MYSQL_TIME::minute= minute;
  MYSQL_TIME::second= (uint) second.sec();
  MYSQL_TIME::second_part= second.usec();
  adjust_time_range_or_invalidate(warn);
}


void Temporal_with_date::make_from_item(THD *thd, Item *item,
                                        date_mode_t fuzzydate)
{
  date_conv_mode_t flags= date_conv_mode_t(fuzzydate) & ~TIME_TIME_ONLY;
  /*
    Some TIME type items return error when trying to do get_date()
    without TIME_TIME_ONLY set (e.g. Item_field for Field_time).
    In the SQL standard time->datetime conversion mode we add TIME_TIME_ONLY.
    In the legacy time->datetime conversion mode we do not add TIME_TIME_ONLY
    and leave it to get_date() to check date.
  */
  date_conv_mode_t time_flag= (item->field_type() == MYSQL_TYPE_TIME &&
              !(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST)) ?
              TIME_TIME_ONLY : TIME_CONV_NONE;
  Options opt(flags | time_flag, time_round_mode_t(fuzzydate));
  if (item->get_date(thd, this, opt))
    time_type= MYSQL_TIMESTAMP_NONE;
  else if (time_type == MYSQL_TIMESTAMP_TIME)
  {
    MYSQL_TIME tmp;
    if (time_to_datetime_with_warn(thd, this, &tmp, flags))
      time_type= MYSQL_TIMESTAMP_NONE;
    else
      *(static_cast<MYSQL_TIME*>(this))= tmp;
  }
}


void Temporal_with_date::check_date_or_invalidate(int *warn,
                                                  date_conv_mode_t flags)
{
  if (::check_date(this, pack_time(this) != 0,
                   ulonglong(flags & TIME_MODE_FOR_XXX_TO_DATE), warn))
    time_type= MYSQL_TIMESTAMP_NONE;
}


void Datetime::make_from_time(THD *thd, int *warn, const MYSQL_TIME *from,
                              date_conv_mode_t flags)
{
  DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_TIME);
  if (time_to_datetime(thd, from, this))
    make_from_out_of_range(warn);
  else
  {
    *warn= 0;
    check_date_or_invalidate(warn, flags);
  }
}


void Datetime::make_from_datetime(THD *thd, int *warn, const MYSQL_TIME *from,
                                  date_conv_mode_t flags)
{
  DBUG_ASSERT(from->time_type == MYSQL_TIMESTAMP_DATE ||
              from->time_type == MYSQL_TIMESTAMP_DATETIME);
  if (from->neg || check_datetime_range(from))
    make_from_out_of_range(warn);
  else
  {
    *warn= 0;
    *(static_cast<MYSQL_TIME*>(this))= *from;
    date_to_datetime(this);
    check_date_or_invalidate(warn, flags);
  }
}


Datetime::Datetime(THD *thd, const timeval &tv)
{
  thd->variables.time_zone->gmt_sec_to_TIME(this, tv.tv_sec);
  second_part= tv.tv_usec;
  thd->time_zone_used= 1;
  DBUG_ASSERT(is_valid_value_slow());
}


Datetime::Datetime(THD *thd, int *warn, const MYSQL_TIME *from,
                   date_conv_mode_t flags)
{
  DBUG_ASSERT(bool(flags & TIME_TIME_ONLY) == false);
  switch (from->time_type) {
  case MYSQL_TIMESTAMP_ERROR:
  case MYSQL_TIMESTAMP_NONE:
    make_from_out_of_range(warn);
    break;
  case MYSQL_TIMESTAMP_TIME:
    make_from_time(thd, warn, from, flags);
    break;
  case MYSQL_TIMESTAMP_DATETIME:
  case MYSQL_TIMESTAMP_DATE:
    make_from_datetime(thd, warn, from, flags);
    break;
  }
  DBUG_ASSERT(is_valid_value_slow());
}


bool Temporal::datetime_add_nanoseconds_or_invalidate(THD *thd, int *warn, ulong nsec)
{
  if (!add_nanoseconds_mmssff(nsec))
    return false;
  /*
    Overflow happened on minutes. Now we need to add 1 hour to the value.
    Catch a special case for the maximum possible date and hour==23, to
    truncate '9999-12-31 23:59:59.9999999' (with 7 fractional digits)
          to '9999-12-31 23:59:59.999999'  (with 6 fractional digits),
    with a warning, instead of returning an error, so this statement:
      INSERT INTO (datetime_column) VALUES ('9999-12-31 23:59:59.9999999');
    inserts a value truncated to 6 fractional digits, instead of zero
    date '0000-00-00 00:00:00.000000'.
  */
  if (year == 9999 && month == 12 && day == 31 && hour == 23)
  {
    minute= 59;
    second= 59;
    second_part= 999999;
    *warn= MYSQL_TIME_WARN_OUT_OF_RANGE;
    return false;
  }
  INTERVAL interval;
  memset(&interval, 0, sizeof(interval));
  interval.hour= 1;
  /*
    date_add_interval cannot handle bad dates with zero YYYY or MM.
    Note, check_date(NO_ZERO_XX) does not check YYYY against zero,
    so let's additionally check it.
  */
  if (year == 0 ||
      check_date(TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE, warn) ||
      date_add_interval(thd, this, INTERVAL_HOUR, interval, false/*no warn*/))
  {
    char buf[MAX_DATE_STRING_REP_LENGTH];
    my_date_to_str(this, buf);
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                        ER_WRONG_VALUE_FOR_TYPE,
                        ER_THD(thd, ER_WRONG_VALUE_FOR_TYPE),
                        "date", buf, "round(datetime)");
    make_from_out_of_range(warn);
    return true;
  }
  return false;
}


bool Temporal::datetime_round_or_invalidate(THD *thd, uint dec, int *warn, ulong nsec)
{
  DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS);
  if (datetime_add_nanoseconds_or_invalidate(thd, warn, nsec))
    return true;
  my_datetime_trunc(this, dec);
  return false;

}


bool Datetime::round_or_invalidate(THD *thd, uint dec, int *warn)
{
  return round_or_invalidate(thd, dec, warn, msec_round_add[dec]);
}


Datetime_from_temporal::Datetime_from_temporal(THD *thd, Item *temporal,
                                               date_conv_mode_t fuzzydate)
 :Datetime(thd, temporal, Options(fuzzydate, TIME_FRAC_NONE))
{
  // Exact rounding mode does not matter
  DBUG_ASSERT(temporal->cmp_type() == TIME_RESULT);
}


Datetime_truncation_not_needed::Datetime_truncation_not_needed(THD *thd, Item *item,
                                                               date_conv_mode_t mode)
 :Datetime(thd, item, Options(mode, TIME_FRAC_NONE))
{
  /*
    The called Datetime() constructor only would truncate nanoseconds if they
    existed (but we know there were no nanoseconds). Here we assert that there
    are also no microsecond digits outside of the scale specified in "dec".
  */
  DBUG_ASSERT(!is_valid_datetime() ||
              fraction_remainder(MY_MIN(item->decimals,
                                        TIME_SECOND_PART_DIGITS)) == 0);
}

/********************************************************************/

uint Type_numeric_attributes::find_max_decimals(Item **item, uint nitems)
{
  uint res= 0;
  for (uint i= 0; i < nitems; i++)
    set_if_bigger(res, item[i]->decimals);
  return res;
}


uint Type_numeric_attributes::count_unsigned(Item **item, uint nitems)
{
  uint res= 0;
  for (uint i= 0 ; i < nitems ; i++)
  {
    if (item[i]->unsigned_flag)
      res++;
  }
  return res;
}


uint32 Type_numeric_attributes::find_max_char_length(Item **item, uint nitems)
{
  uint32 char_length= 0;
  for (uint i= 0; i < nitems ; i++)
    set_if_bigger(char_length, item[i]->max_char_length());
  return char_length;
}


uint32 Type_numeric_attributes::find_max_octet_length(Item **item, uint nitems)
{
  uint32 octet_length= 0;
  for (uint i= 0; i < nitems ; i++)
    set_if_bigger(octet_length, item[i]->max_length);
  return octet_length;
}


int Type_numeric_attributes::find_max_decimal_int_part(Item **item, uint nitems)
{
  int max_int_part= 0;
  for (uint i=0 ; i < nitems ; i++)
    set_if_bigger(max_int_part, item[i]->decimal_int_part());
  return max_int_part;
}


/**
  Set max_length/decimals of function if function is fixed point and
  result length/precision depends on argument ones.
*/

void
Type_numeric_attributes::aggregate_numeric_attributes_decimal(Item **item,
                                                              uint nitems,
                                                              bool unsigned_arg)
{
  int max_int_part= find_max_decimal_int_part(item, nitems);
  decimals= find_max_decimals(item, nitems);
  int precision= MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION);
  max_length= my_decimal_precision_to_length_no_truncation(precision,
                                                           (uint8) decimals,
                                                           unsigned_flag);
}


/**
  Set max_length/decimals of function if function is floating point and
  result length/precision depends on argument ones.
*/

void
Type_numeric_attributes::aggregate_numeric_attributes_real(Item **items,
                                                           uint nitems)
{
  uint32 length= 0;
  decimals= 0;
  max_length= 0;
  unsigned_flag= false;
  for (uint i=0 ; i < nitems ; i++)
  {
    if (decimals < FLOATING_POINT_DECIMALS)
    {
      set_if_bigger(decimals, items[i]->decimals);
      /* Will be ignored if items[i]->decimals >= FLOATING_POINT_DECIMALS */
      set_if_bigger(length, (items[i]->max_length - items[i]->decimals));
    }
    set_if_bigger(max_length, items[i]->max_length);
  }
  if (decimals < FLOATING_POINT_DECIMALS)
  {
    max_length= length;
    length+= decimals;
    if (length < max_length)  // If previous operation gave overflow
      max_length= UINT_MAX32;
    else
      max_length= length;
  }
  // Corner case: COALESCE(DOUBLE(255,4), DOUBLE(255,3)) -> FLOAT(255, 4)
  set_if_smaller(max_length, MAX_FIELD_CHARLENGTH);
}


/**
  Calculate max_length and decimals for string functions.

  @param field_type  Field type.
  @param items       Argument array.
  @param nitems      Number of arguments.

  @retval            False on success, true on error.
*/
bool Type_std_attributes::aggregate_attributes_string(const char *func_name,
                                                      Item **items, uint nitems)
{
  if (agg_arg_charsets_for_string_result(collation, func_name,
                                         items, nitems, 1))
    return true;
  if (collation.collation == &my_charset_bin)
    max_length= find_max_octet_length(items, nitems);
  else
    fix_char_length(find_max_char_length(items, nitems));
  unsigned_flag= false;
  decimals= max_length ? NOT_FIXED_DEC : 0;
  return false;
}


/*
  Find a handler by its ODBC literal data type.

  @param type_str  - data type name, not necessarily 0-terminated
  @retval          - a pointer to data type handler if type_str points
                     to a known ODBC literal data type, or NULL otherwise
*/
const Type_handler *
Type_handler::odbc_literal_type_handler(const LEX_CSTRING *type_str)
{
  if (type_str->length == 1)
  {
    if (type_str->str[0] == 'd')      // {d'2001-01-01'}
      return &type_handler_newdate;
    else if (type_str->str[0] == 't') // {t'10:20:30'}
      return &type_handler_time2;
  }
  else if (type_str->length == 2)     // {ts'2001-01-01 10:20:30'}
  {
    if (type_str->str[0] == 't' && type_str->str[1] == 's')
      return &type_handler_datetime2;
  }
  return NULL; // Not a known ODBC literal type
}


/**
  This method is used by:
  - Item_user_var_as_out_param::field_type()
  - Item_func_udf_str::field_type()
  - Item_empty_string::make_send_field()

  TODO: type_handler_adjusted_to_max_octet_length() and string_type_handler()
  provide very similar functionality, to properly choose between
  VARCHAR/VARBINARY vs TEXT/BLOB variations taking into accoung maximum
  possible octet length.

  We should probably get rid of either of them and use the same method
  all around the code.
*/
const Type_handler *
Type_handler::string_type_handler(uint max_octet_length)
{
  if (max_octet_length >= 16777216)
    return &type_handler_long_blob;
  else if (max_octet_length >= 65536)
    return &type_handler_medium_blob;
  else if (max_octet_length >= MAX_FIELD_VARCHARLENGTH)
    return &type_handler_blob;
  return &type_handler_varchar;
}


const Type_handler *
Type_handler::varstring_type_handler(const Item *item)
{
  if (!item->max_length)
    return &type_handler_string;
  if (item->too_big_for_varchar())
    return blob_type_handler(item->max_length);
  return &type_handler_varchar;
}


const Type_handler *
Type_handler::blob_type_handler(uint max_octet_length)
{
  if (max_octet_length <= 255)
    return &type_handler_tiny_blob;
  if (max_octet_length <= 65535)
    return &type_handler_blob;
  if (max_octet_length <= 16777215)
    return &type_handler_medium_blob;
  return &type_handler_long_blob;
}


const Type_handler *
Type_handler::blob_type_handler(const Item *item)
{
  return blob_type_handler(item->max_length);
}

/**
  This method is used by:
  - Item_sum_hybrid, e.g. MAX(item), MIN(item).
  - Item_func_set_user_var
*/
const Type_handler *
Type_handler_string_result::type_handler_adjusted_to_max_octet_length(
                                                        uint max_octet_length,
                                                        CHARSET_INFO *cs) const
{
  if (max_octet_length / cs->mbmaxlen <= CONVERT_IF_BIGGER_TO_BLOB)
    return &type_handler_varchar; // See also Item::too_big_for_varchar()
  if (max_octet_length >= 16777216)
    return &type_handler_long_blob;
  else if (max_octet_length >= 65536)
    return &type_handler_medium_blob;
  return &type_handler_blob;
}


CHARSET_INFO *Type_handler::charset_for_protocol(const Item *item) const
{
  /*
    For backward compatibility, to make numeric
    data types return "binary" charset in client-side metadata.
  */
  return &my_charset_bin;
}


bool
Type_handler::Item_func_or_sum_illegal_param(const char *funcname) const
{
  my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
           name().ptr(), funcname);
  return true;
}


bool
Type_handler::Item_func_or_sum_illegal_param(const Item_func_or_sum *it) const
{
  return Item_func_or_sum_illegal_param(it->func_name());
}


CHARSET_INFO *
Type_handler_string_result::charset_for_protocol(const Item *item) const
{
  return item->collation.collation;
}


const Type_handler *
Type_handler::get_handler_by_cmp_type(Item_result type)
{
  switch (type) {
  case REAL_RESULT:       return &type_handler_double;
  case INT_RESULT:        return &type_handler_slonglong;
  case DECIMAL_RESULT:    return &type_handler_newdecimal;
  case STRING_RESULT:     return &type_handler_long_blob;
  case TIME_RESULT:       return &type_handler_datetime;
  case ROW_RESULT:        return &type_handler_row;
  }
  DBUG_ASSERT(0);
  return &type_handler_string;
}


/*
  If we have a mixture of:
  - a MariaDB standard (built-in permanent) data type, and
  - a non-standard (optionally compiled or pluggable) data type,
  then we ask the type collection of the non-standard type to aggregate
  the mixture.
  The standard type collection type_collection_std knows nothing
  about non-standard types, while non-standard type collections
  know everything about standard data types.
*/
const Type_collection *
Type_handler::type_collection_for_aggregation(const Type_handler *h0,
                                              const Type_handler *h1)
{
  const Type_collection *c0= h0->type_collection();
  const Type_collection *c1= h1->type_collection();
  if (c0 == c1)
    return c0;
  if (c0 == &type_collection_std)
    return c1;
  if (c1 == &type_collection_std)
    return c0;
  /*
    A mixture of two non-standard collections.
    The caller code will continue to aggregate through
    the type aggregators in Type_handler_data.
  */
  return NULL;
}


Type_handler_hybrid_field_type::Type_handler_hybrid_field_type()
  :m_type_handler(&type_handler_double)
{
}


/***************************************************************************/

/* number of bytes to store second_part part of the TIMESTAMP(N) */
uint Type_handler_timestamp::m_sec_part_bytes[MAX_DATETIME_PRECISION + 1]=
     { 0, 1, 1, 2, 2, 3, 3 };

/* number of bytes to store DATETIME(N) */
uint Type_handler_datetime::m_hires_bytes[MAX_DATETIME_PRECISION + 1]=
     { 5, 6, 6, 7, 7, 7, 8 };

/* number of bytes to store TIME(N) */
uint Type_handler_time::m_hires_bytes[MAX_DATETIME_PRECISION + 1]=
     { 3, 4, 4, 5, 5, 5, 6 };

/***************************************************************************/

const Name Type_handler::version() const
{
  static const Name ver(STRING_WITH_LEN(""));
  return ver;
}

const Name & Type_handler::version_mariadb53()
{
  static const Name ver(STRING_WITH_LEN("mariadb-5.3"));
  return ver;
}

const Name & Type_handler::version_mysql56()
{
  static const Name ver(STRING_WITH_LEN("mysql-5.6"));
  return ver;
}


/***************************************************************************/

const Type_limits_int *Type_handler_tiny::type_limits_int() const
{
  static const Type_limits_sint8 limits_sint8;
  return &limits_sint8;
}

const Type_limits_int *Type_handler_utiny::type_limits_int() const
{
  static const Type_limits_uint8 limits_uint8;
  return &limits_uint8;
}

const Type_limits_int *Type_handler_short::type_limits_int() const
{
  static const Type_limits_sint16 limits_sint16;
  return &limits_sint16;
}

const Type_limits_int *Type_handler_ushort::type_limits_int() const
{
  static const Type_limits_uint16 limits_uint16;
  return &limits_uint16;
}

const Type_limits_int *Type_handler_int24::type_limits_int() const
{
  static const Type_limits_sint24 limits_sint24;
  return &limits_sint24;
}

const Type_limits_int *Type_handler_uint24::type_limits_int() const
{
  static const Type_limits_uint24 limits_uint24;
  return &limits_uint24;
}

const Type_limits_int *Type_handler_long::type_limits_int() const
{
  static const Type_limits_sint32 limits_sint32;
  return &limits_sint32;
}

const Type_limits_int *Type_handler_ulong::type_limits_int() const
{
  static const Type_limits_uint32 limits_uint32;
  return &limits_uint32;
}

const Type_limits_int *Type_handler_longlong::type_limits_int() const
{
  static const Type_limits_sint64 limits_sint64;
  return &limits_sint64;
}

const Type_limits_int *Type_handler_ulonglong::type_limits_int() const
{
  static const Type_limits_uint64 limits_uint64;
  return &limits_uint64;
}


/***************************************************************************/
const Type_handler *Type_handler_bool::type_handler_signed() const
{
  return &type_handler_bool;
}

const Type_handler *Type_handler_bool::type_handler_unsigned() const
{
  return &type_handler_bool;
}

const Type_handler *Type_handler_tiny::type_handler_signed() const
{
  return &type_handler_stiny;
}

const Type_handler *Type_handler_tiny::type_handler_unsigned() const
{
  return &type_handler_utiny;
}

const Type_handler *Type_handler_short::type_handler_signed() const
{
  return &type_handler_sshort;
}

const Type_handler *Type_handler_short::type_handler_unsigned() const
{
  return &type_handler_ushort;
}

const Type_handler *Type_handler_int24::type_handler_signed() const
{
  return &type_handler_sint24;
}

const Type_handler *Type_handler_int24::type_handler_unsigned() const
{
  return &type_handler_uint24;
}

const Type_handler *Type_handler_long::type_handler_signed() const
{
  return &type_handler_slong;
}

const Type_handler *Type_handler_long::type_handler_unsigned() const
{
  return &type_handler_ulong;
}

const Type_handler *Type_handler_longlong::type_handler_signed() const
{
  return &type_handler_slonglong;
}

const Type_handler *Type_handler_longlong::type_handler_unsigned() const
{
  return &type_handler_ulonglong;
}

/***************************************************************************/

const Type_handler *Type_handler_null::type_handler_for_comparison() const
{
  return &type_handler_null;
}


const Type_handler *Type_handler_int_result::type_handler_for_comparison() const
{
  return &type_handler_slonglong;
}


const Type_handler *Type_handler_string_result::type_handler_for_comparison() const
{
  return &type_handler_long_blob;
}


const Type_handler *Type_handler_decimal_result::type_handler_for_comparison() const
{
  return &type_handler_newdecimal;
}


const Type_handler *Type_handler_real_result::type_handler_for_comparison() const
{
  return &type_handler_double;
}


const Type_handler *Type_handler_time_common::type_handler_for_comparison() const
{
  return &type_handler_time;
}

const Type_handler *Type_handler_date_common::type_handler_for_comparison() const
{
  return &type_handler_newdate;
}


const Type_handler *Type_handler_datetime_common::type_handler_for_comparison() const
{
  return &type_handler_datetime;
}


const Type_handler *Type_handler_timestamp_common::type_handler_for_comparison() const
{
  return &type_handler_timestamp;
}


const Type_handler *Type_handler_row::type_handler_for_comparison() const
{
  return &type_handler_row;
}

/***************************************************************************/

const Type_handler *
Type_handler_timestamp_common::type_handler_for_native_format() const
{
  return &type_handler_timestamp2;
}


const Type_handler *
Type_handler_time_common::type_handler_for_native_format() const
{
  return &type_handler_time2;
}


/***************************************************************************/

const Type_handler *Type_handler_typelib::type_handler_for_item_field() const
{
  return &type_handler_string;
}


const Type_handler *Type_handler_typelib::cast_to_int_type_handler() const
{
  return &type_handler_slonglong;
}


/***************************************************************************/

bool
Type_handler_hybrid_field_type::aggregate_for_result(const Type_handler *other)
{
  const Type_handler *hres;
  const Type_collection *c;
  if (!(c= Type_handler::type_collection_for_aggregation(m_type_handler, other)) ||
      !(hres= c->aggregate_for_result(m_type_handler, other)))
    hres= type_handler_data->
            m_type_aggregator_for_result.find_handler(m_type_handler, other);
  if (!hres)
    return true;
  m_type_handler= hres;
  return false;
}


const Type_handler *
Type_handler::type_handler_long_or_longlong(uint max_char_length,
                                            bool unsigned_flag)
{
  if (unsigned_flag)
  {
    if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS - 2)
      return &type_handler_ulong;
    return &type_handler_ulonglong;
  }
  if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS - 2)
    return &type_handler_slong;
  return &type_handler_slonglong;
}


/*
  This method is called for CASE (and its abbreviations) and LEAST/GREATEST
  when data type aggregation returned LONGLONG and there were some BIT
  expressions. This helps to adjust the data type from LONGLONG to LONG
  if all expressions fit.
*/
const Type_handler *
Type_handler::bit_and_int_mixture_handler(uint max_char_length)
{
  if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS)
    return &type_handler_slong;
  return &type_handler_slonglong;
}


/**
  @brief Aggregates field types from the array of items.

  @param[in] items  array of items to aggregate the type from
  @param[in] nitems number of items in the array
  @param[in] treat_bit_as_number - if BIT should be aggregated to a non-BIT
             counterpart as a LONGLONG number or as a VARBINARY string.

             Currently behaviour depends on the function:
             - LEAST/GREATEST treat BIT as VARBINARY when
               aggregating with a non-BIT counterpart.
               Note, UNION also works this way.

             - CASE, COALESCE, IF, IFNULL treat BIT as LONGLONG when
               aggregating with a non-BIT counterpart;

             This inconsistency may be changed in the future. See MDEV-8867.

             Note, independently from "treat_bit_as_number":
             - a single BIT argument gives BIT as a result
             - two BIT couterparts give BIT as a result

  @details This function aggregates field types from the array of items.
    Found type is supposed to be used later as the result field type
    of a multi-argument function.
    Aggregation itself is performed by Type_handler::aggregate_for_result().

  @note The term "aggregation" is used here in the sense of inferring the
    result type of a function from its argument types.

  @retval false - on success
  @retval true  - on error
*/

bool
Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname,
                                                     Item **items, uint nitems,
                                                     bool treat_bit_as_number)
{
  bool bit_and_non_bit_mixture_found= false;
  uint32 max_display_length;
  if (!nitems || items[0]->result_type() == ROW_RESULT)
  {
    DBUG_ASSERT(0);
    set_handler(&type_handler_null);
    return true;
  }
  set_handler(items[0]->type_handler());
  max_display_length= items[0]->max_display_length();
  for (uint i= 1 ; i < nitems ; i++)
  {
    const Type_handler *cur= items[i]->type_handler();
    set_if_bigger(max_display_length, items[i]->max_display_length());
    if (treat_bit_as_number &&
        ((type_handler() == &type_handler_bit) ^ (cur == &type_handler_bit)))
    {
      bit_and_non_bit_mixture_found= true;
      if (type_handler() == &type_handler_bit)
        set_handler(&type_handler_slonglong); // BIT + non-BIT
      else
        cur= &type_handler_slonglong; // non-BIT + BIT
    }
    if (aggregate_for_result(cur))
    {
      my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
               type_handler()->name().ptr(), cur->name().ptr(), funcname);
      return true;
    }
  }
  if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_slonglong)
    set_handler(Type_handler::bit_and_int_mixture_handler(max_display_length));
  return false;
}

/**
  Collect built-in data type handlers for comparison.
  This method is very similar to item_cmp_type() defined in item.cc.
  Now they coexist. Later item_cmp_type() will be removed.
  In addition to item_cmp_type(), this method correctly aggregates
  TIME with DATETIME/TIMESTAMP/DATE, so no additional find_date_time_item()
  is needed after this call.
*/

bool
Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
{
  DBUG_ASSERT(m_type_handler == m_type_handler->type_handler_for_comparison());
  DBUG_ASSERT(h == h->type_handler_for_comparison());
  const Type_handler *hres;
  const Type_collection *c;
  if (!(c= Type_handler::type_collection_for_aggregation(m_type_handler, h)) ||
      !(hres= c->aggregate_for_comparison(m_type_handler, h)))
    hres= type_handler_data->
            m_type_aggregator_for_comparison.find_handler(m_type_handler, h);
  if (!hres)
    return true;
  m_type_handler= hres;
  DBUG_ASSERT(m_type_handler == m_type_handler->type_handler_for_comparison());
  return false;
}


const Type_handler *
Type_collection_std::aggregate_for_comparison(const Type_handler *ha,
                                              const Type_handler *hb) const
{
  Item_result a= ha->cmp_type();
  Item_result b= hb->cmp_type();
  if (a == STRING_RESULT && b == STRING_RESULT)
    return &type_handler_long_blob;
  if (a == INT_RESULT && b == INT_RESULT)
    return &type_handler_slonglong;
  if (a == ROW_RESULT || b == ROW_RESULT)
    return &type_handler_row;
  if (a == TIME_RESULT || b == TIME_RESULT)
  {
    if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1)
    {
      /*
        We're here if there's only one temporal data type:
        either m_type_handler or h.
        Temporal types bit non-temporal types.
      */
      const Type_handler *res= b == TIME_RESULT ? hb : ha;
      /*
        Compare TIMESTAMP to a non-temporal type as DATETIME.
        This is needed to make queries with fuzzy dates work:
        SELECT * FROM t1
        WHERE
          ts BETWEEN '0000-00-00' AND '2010-00-01 00:00:00';
      */
      if (res->type_handler_for_native_format() == &type_handler_timestamp2)
        return &type_handler_datetime;
      return res;
    }
    else
    {
      /*
        We're here if both m_type_handler and h are temporal data types.
        - If both data types are TIME, we preserve TIME.
        - If both data types are DATE, we preserve DATE.
          Preserving DATE is needed for EXPLAIN FORMAT=JSON,
          to print DATE constants using proper format:
          'YYYY-MM-DD' rather than 'YYYY-MM-DD 00:00:00'.
      */
      if (ha->field_type() != hb->field_type())
        return &type_handler_datetime;
      return ha;
    }
  }
  if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
      (b == INT_RESULT || b == DECIMAL_RESULT))
    return &type_handler_newdecimal;
  return &type_handler_double;
}


/**
  Aggregate data type handler for LEAST/GRATEST.
  aggregate_for_min_max() is close to aggregate_for_comparison(),
  but tries to preserve the exact type handler for string, int and temporal
  data types (instead of converting to super-types).
  FLOAT is not preserved and is converted to its super-type (DOUBLE).
  This should probably fixed eventually, for symmetry.
*/

bool
Type_handler_hybrid_field_type::aggregate_for_min_max(const Type_handler *h)
{
  const Type_handler *hres;
  const Type_collection *c;
  if (!(c= Type_handler::type_collection_for_aggregation(m_type_handler, h))||
      !(hres= c->aggregate_for_min_max(m_type_handler, h)))
  {
    /*
      For now we suppose that these two expressions:
        - LEAST(type1, type2)
        - COALESCE(type1, type2)
      return the same data type (or both expressions return error)
      if type1 and/or type2 are non-traditional.
      This may change in the future.
    */
    hres= type_handler_data->
            m_type_aggregator_for_result.find_handler(m_type_handler, h);
  }
  if (!hres)
    return true;
  m_type_handler= hres;
  return false;
}


const Type_handler *
Type_collection_std::aggregate_for_min_max(const Type_handler *ha,
                                           const Type_handler *hb) const
{
  Item_result a= ha->cmp_type();
  Item_result b= hb->cmp_type();
  DBUG_ASSERT(a != ROW_RESULT); // Disallowed by check_cols() in fix_fields()
  DBUG_ASSERT(b != ROW_RESULT); // Disallowed by check_cols() in fix_fields()

  if (a == STRING_RESULT && b == STRING_RESULT)
    return Type_collection_std::aggregate_for_result(ha, hb);
  if (a == INT_RESULT && b == INT_RESULT)
  {
    // BIT aggregates with non-BIT as BIGINT
    if (ha != hb)
    {
      if (ha == &type_handler_bit)
        ha= &type_handler_slonglong;
      else if (hb == &type_handler_bit)
        hb= &type_handler_slonglong;
    }
    return Type_collection_std::aggregate_for_result(ha, hb);
  }
  if (a == TIME_RESULT || b == TIME_RESULT)
  {
    if ((ha->type_handler_for_native_format() == &type_handler_timestamp2) +
        (hb->type_handler_for_native_format() == &type_handler_timestamp2) == 1)
    {
      /*
        Handle LEAST(TIMESTAMP, non-TIMESTAMP) as DATETIME,
        to make sure fuzzy dates work in this context:
          LEAST('2001-00-00', timestamp_field)
      */
      return &type_handler_datetime2;
    }
    if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1)
    {
      /*
        We're here if there's only one temporal data type:
        either m_type_handler or h.
        Temporal types bit non-temporal types.
      */
      return (b == TIME_RESULT) ? hb : ha;
    }
    /*
      We're here if both m_type_handler and h are temporal data types.
    */
    return Type_collection_std::aggregate_for_result(ha, hb);
  }
  if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
      (b == INT_RESULT || b == DECIMAL_RESULT))
  {
    return &type_handler_newdecimal;
  }
  // Preserve FLOAT if two FLOATs, set to DOUBLE otherwise.
  if (ha == &type_handler_float && hb == &type_handler_float)
    return &type_handler_float;
  return &type_handler_double;
}


bool
Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname,
                                                      Item **items, uint nitems)
{
  bool bit_and_non_bit_mixture_found= false;
  // LEAST/GREATEST require at least two arguments
  DBUG_ASSERT(nitems > 1);
  set_handler(items[0]->type_handler());
  for (uint i= 1; i < nitems;  i++)
  {
    const Type_handler *cur= items[i]->type_handler();
    // Check if BIT + non-BIT, or non-BIT + BIT
    bit_and_non_bit_mixture_found|= (m_type_handler == &type_handler_bit) !=
                                    (cur == &type_handler_bit);
    if (aggregate_for_min_max(cur))
    {
      my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
               type_handler()->name().ptr(), cur->name().ptr(), funcname);
      return true;
    }
  }
  if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_slonglong)
  {
    uint32 max_display_length= items[0]->max_display_length();
    for (uint i= 1; i < nitems; i++)
      set_if_bigger(max_display_length, items[i]->max_display_length());
    set_handler(Type_handler::bit_and_int_mixture_handler(max_display_length));
  }
  return false;
}


const Type_handler *
Type_collection_std::aggregate_for_num_op(const Type_handler *h0,
                                          const Type_handler *h1) const
{
  Item_result r0= h0->cmp_type();
  Item_result r1= h1->cmp_type();

  if (r0 == REAL_RESULT || r1 == REAL_RESULT ||
      r0 == STRING_RESULT || r1 ==STRING_RESULT)
    return &type_handler_double;

  if (r0 == TIME_RESULT || r1 == TIME_RESULT)
    return &type_handler_datetime;

  if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT)
    return &type_handler_newdecimal;

  DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT);
  return &type_handler_slonglong;
}


const Type_aggregator::Pair*
Type_aggregator::find_pair(const Type_handler *handler1,
                           const Type_handler *handler2) const
{
  for (uint i= 0; i < m_array.elements(); i++)
  {
    const Pair& el= m_array.at(i);
    if (el.eq(handler1, handler2) ||
        (m_is_commutative && el.eq(handler2, handler1)))
      return &el;
  }
  return NULL;
}


bool
Type_handler_hybrid_field_type::aggregate_for_num_op(const Type_aggregator *agg,
                                                     const Type_handler *h0,
                                                     const Type_handler *h1)
{
  const Type_handler *hres;
  const Type_collection *c;
  if (!(c= Type_handler::type_collection_for_aggregation(h0, h1)) ||
      !(hres= c->aggregate_for_num_op(h0, h1)))
    hres= agg->find_handler(h0, h1);
  if (!hres)
    return true;
  m_type_handler= hres;
  return false;
}


/***************************************************************************/

const Type_handler *
Type_handler::get_handler_by_field_type(enum_field_types type)
{
  switch (type) {
  case MYSQL_TYPE_DECIMAL:     return &type_handler_olddecimal;
  case MYSQL_TYPE_NEWDECIMAL:  return &type_handler_newdecimal;
  case MYSQL_TYPE_TINY:        return &type_handler_stiny;
  case MYSQL_TYPE_SHORT:       return &type_handler_sshort;
  case MYSQL_TYPE_LONG:        return &type_handler_slong;
  case MYSQL_TYPE_LONGLONG:    return &type_handler_slonglong;
  case MYSQL_TYPE_INT24:       return &type_handler_sint24;
  case MYSQL_TYPE_YEAR:        return &type_handler_year;
  case MYSQL_TYPE_BIT:         return &type_handler_bit;
  case MYSQL_TYPE_FLOAT:       return &type_handler_float;
  case MYSQL_TYPE_DOUBLE:      return &type_handler_double;
  case MYSQL_TYPE_NULL:        return &type_handler_null;
  case MYSQL_TYPE_VARCHAR:     return &type_handler_varchar;
  case MYSQL_TYPE_TINY_BLOB:   return &type_handler_tiny_blob;
  case MYSQL_TYPE_MEDIUM_BLOB: return &type_handler_medium_blob;
  case MYSQL_TYPE_LONG_BLOB:   return &type_handler_long_blob;
  case MYSQL_TYPE_BLOB:        return &type_handler_blob;
  case MYSQL_TYPE_VAR_STRING:  return &type_handler_varchar; // Map to VARCHAR 
  case MYSQL_TYPE_STRING:      return &type_handler_string;
  case MYSQL_TYPE_ENUM:        return &type_handler_varchar; // Map to VARCHAR
  case MYSQL_TYPE_SET:         return &type_handler_varchar; // Map to VARCHAR
  case MYSQL_TYPE_GEOMETRY:
#ifdef HAVE_SPATIAL
    return &type_handler_geometry;
#else
    return NULL;
#endif
  case MYSQL_TYPE_TIMESTAMP:   return &type_handler_timestamp2;// Map to timestamp2
  case MYSQL_TYPE_TIMESTAMP2:  return &type_handler_timestamp2;
  case MYSQL_TYPE_DATE:        return &type_handler_newdate;   // Map to newdate
  case MYSQL_TYPE_TIME:        return &type_handler_time2;     // Map to time2
  case MYSQL_TYPE_TIME2:       return &type_handler_time2;
  case MYSQL_TYPE_DATETIME:    return &type_handler_datetime2; // Map to datetime2
  case MYSQL_TYPE_DATETIME2:   return &type_handler_datetime2;
  case MYSQL_TYPE_NEWDATE:
    /*
      NEWDATE is actually a real_type(), not a field_type(),
      but it's used around the code in field_type() context.
      We should probably clean up the code not to use MYSQL_TYPE_NEWDATE
      in field_type() context and add DBUG_ASSERT(0) here.
    */
    return &type_handler_newdate;
  case MYSQL_TYPE_VARCHAR_COMPRESSED:
  case MYSQL_TYPE_BLOB_COMPRESSED:
    break;
  };
  DBUG_ASSERT(0);
  return &type_handler_string;
}


const Type_handler *
Type_handler::get_handler_by_real_type(enum_field_types type)
{
  switch (type) {
  case MYSQL_TYPE_DECIMAL:     return &type_handler_olddecimal;
  case MYSQL_TYPE_NEWDECIMAL:  return &type_handler_newdecimal;
  case MYSQL_TYPE_TINY:        return &type_handler_stiny;
  case MYSQL_TYPE_SHORT:       return &type_handler_sshort;
  case MYSQL_TYPE_LONG:        return &type_handler_slong;
  case MYSQL_TYPE_LONGLONG:    return &type_handler_slonglong;
  case MYSQL_TYPE_INT24:       return &type_handler_sint24;
  case MYSQL_TYPE_YEAR:        return &type_handler_year;
  case MYSQL_TYPE_BIT:         return &type_handler_bit;
  case MYSQL_TYPE_FLOAT:       return &type_handler_float;
  case MYSQL_TYPE_DOUBLE:      return &type_handler_double;
  case MYSQL_TYPE_NULL:        return &type_handler_null;
  case MYSQL_TYPE_VARCHAR:     return &type_handler_varchar;
  case MYSQL_TYPE_VARCHAR_COMPRESSED: return &type_handler_varchar_compressed;
  case MYSQL_TYPE_TINY_BLOB:   return &type_handler_tiny_blob;
  case MYSQL_TYPE_MEDIUM_BLOB: return &type_handler_medium_blob;
  case MYSQL_TYPE_LONG_BLOB:   return &type_handler_long_blob;
  case MYSQL_TYPE_BLOB:        return &type_handler_blob;
  case MYSQL_TYPE_BLOB_COMPRESSED: return &type_handler_blob_compressed;
  case MYSQL_TYPE_VAR_STRING:  return &type_handler_var_string;
  case MYSQL_TYPE_STRING:      return &type_handler_string;
  case MYSQL_TYPE_ENUM:        return &type_handler_enum;
  case MYSQL_TYPE_SET:         return &type_handler_set;
  case MYSQL_TYPE_GEOMETRY:
#ifdef HAVE_SPATIAL
    return &type_handler_geometry;
#else
    return NULL;
#endif
  case MYSQL_TYPE_TIMESTAMP:   return &type_handler_timestamp;
  case MYSQL_TYPE_TIMESTAMP2:  return &type_handler_timestamp2;
  case MYSQL_TYPE_DATE:        return &type_handler_date;
  case MYSQL_TYPE_TIME:        return &type_handler_time;
  case MYSQL_TYPE_TIME2:       return &type_handler_time2;
  case MYSQL_TYPE_DATETIME:    return &type_handler_datetime;
  case MYSQL_TYPE_DATETIME2:   return &type_handler_datetime2;
  case MYSQL_TYPE_NEWDATE:     return &type_handler_newdate;
  };
  return NULL;
}


/**
  Create a DOUBLE field by default.
*/
Field *
Type_handler::make_num_distinct_aggregator_field(MEM_ROOT *mem_root,
                                                 const Item *item) const
{
  return new(mem_root)
         Field_double(NULL, item->max_length,
                      (uchar *) (item->maybe_null ? "" : 0),
                      item->maybe_null ? 1 : 0, Field::NONE,
                      &item->name, (uint8) item->decimals,
                      0, item->unsigned_flag);
}


Field *
Type_handler_float::make_num_distinct_aggregator_field(MEM_ROOT *mem_root,
                                                       const Item *item)
                                                       const
{
  return new(mem_root)
         Field_float(NULL, item->max_length,
                     (uchar *) (item->maybe_null ? "" : 0),
                     item->maybe_null ? 1 : 0, Field::NONE,
                     &item->name, (uint8) item->decimals,
                     0, item->unsigned_flag);
}


Field *
Type_handler_decimal_result::make_num_distinct_aggregator_field(
                                                            MEM_ROOT *mem_root,
                                                            const Item *item)
                                                            const
{
  DBUG_ASSERT(item->decimals <= DECIMAL_MAX_SCALE);
  return new (mem_root)
         Field_new_decimal(NULL, item->max_length,
                           (uchar *) (item->maybe_null ? "" : 0),
                           item->maybe_null ? 1 : 0, Field::NONE,
                           &item->name, (uint8) item->decimals,
                           0, item->unsigned_flag);
}


Field *
Type_handler_int_result::make_num_distinct_aggregator_field(MEM_ROOT *mem_root,
                                                            const Item *item)
                                                            const
{
  /**
    Make a longlong field for all INT-alike types. It could create
    smaller fields for TINYINT, SMALLINT, MEDIUMINT, INT though.
  */
  return new(mem_root)
         Field_longlong(NULL, item->max_length,
                        (uchar *) (item->maybe_null ? "" : 0),
                        item->maybe_null ? 1 : 0, Field::NONE,
                        &item->name, 0, item->unsigned_flag);
}


/***********************************************************************/

Field *Type_handler_tiny::make_conversion_table_field(MEM_ROOT *root,
                                                      TABLE *table,
                                                      uint metadata,
                                                      const Field *target)
                                                      const
{
  /*
    As we don't know if the integer was signed or not on the master,
    assume we have same sign on master and slave.  This is true when not
    using conversions so it should be true also when using conversions.
  */
  bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
  return new (root)
         Field_tiny(NULL, 4 /*max_length*/, (uchar *) "", 1, Field::NONE,
                    &empty_clex_str, 0/*zerofill*/, unsigned_flag);
}


Field *Type_handler_short::make_conversion_table_field(MEM_ROOT *root,
                                                       TABLE *table,
                                                       uint metadata,
                                                       const Field *target)
                                                       const
{
  bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
  return new (root)
         Field_short(NULL, 6 /*max_length*/, (uchar *) "", 1, Field::NONE,
                     &empty_clex_str, 0/*zerofill*/, unsigned_flag);
}


Field *Type_handler_int24::make_conversion_table_field(MEM_ROOT *root,
                                                       TABLE *table,
                                                       uint metadata,
                                                       const Field *target)
                                                       const
{
  bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
  return new (root)
         Field_medium(NULL, 9 /*max_length*/, (uchar *) "", 1, Field::NONE,
                      &empty_clex_str, 0/*zerofill*/, unsigned_flag);
}


Field *Type_handler_long::make_conversion_table_field(MEM_ROOT *root,
                                                      TABLE *table,
                                                      uint metadata,
                                                      const Field *target)
                                                      const
{
  bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
  return new (root)
         Field_long(NULL, 11 /*max_length*/, (uchar *) "", 1, Field::NONE,
         &empty_clex_str, 0/*zerofill*/, unsigned_flag);
}


Field *Type_handler_longlong::make_conversion_table_field(MEM_ROOT *root,
                                                          TABLE *table,
                                                          uint metadata,
                                                          const Field *target)
                                                          const
{
  bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
  return new (root)
         Field_longlong(NULL, 20 /*max_length*/,(uchar *) "", 1, Field::NONE,
                        &empty_clex_str, 0/*zerofill*/, unsigned_flag);
}



Field *Type_handler_float::make_conversion_table_field(MEM_ROOT *root,
                                                       TABLE *table,
                                                       uint metadata,
                                                       const Field *target)
                                                       const
{
  return new (root)
         Field_float(NULL, 12 /*max_length*/, (uchar *) "", 1, Field::NONE,
                     &empty_clex_str, 0/*dec*/, 0/*zerofill*/, 0/*unsigned_flag*/);
}


Field *Type_handler_double::make_conversion_table_field(MEM_ROOT *root,
                                                        TABLE *table,
                                                        uint metadata,
                                                        const Field *target)
                                                        const
{
  return new (root)
         Field_double(NULL, 22 /*max_length*/, (uchar *) "", 1, Field::NONE,
                      &empty_clex_str, 0/*dec*/, 0/*zerofill*/, 0/*unsigned_flag*/);
}


Field *Type_handler_newdecimal::make_conversion_table_field(MEM_ROOT *root, 
                                                            TABLE *table,
                                                            uint metadata,
                                                            const Field *target)
                                                            const
{
  int  precision= metadata >> 8;
  uint8 decimals= metadata & 0x00ff;
  uint32 max_length= my_decimal_precision_to_length(precision, decimals, false);
  DBUG_ASSERT(decimals <= DECIMAL_MAX_SCALE);
  return new (root)
         Field_new_decimal(NULL, max_length, (uchar *) "", 1, Field::NONE,
                           &empty_clex_str, decimals, 0/*zerofill*/, 0/*unsigned*/);
}


Field *Type_handler_olddecimal::make_conversion_table_field(MEM_ROOT *root,
                                                            TABLE *table,
                                                            uint metadata,
                                                            const Field *target)
                                                            const
{
  sql_print_error("In RBR mode, Slave received incompatible DECIMAL field "
                  "(old-style decimal field) from Master while creating "
                  "conversion table. Please consider changing datatype on "
                  "Master to new style decimal by executing ALTER command for"
                  " column Name: %s.%s.%s.",
                  target->table->s->db.str,
                  target->table->s->table_name.str,
                  target->field_name.str);
  return NULL;
}


Field *Type_handler_year::make_conversion_table_field(MEM_ROOT *root,
                                                      TABLE *table,
                                                      uint metadata,
                                                      const Field *target)
                                                      const
{
  return new(root)
         Field_year(NULL, 4, (uchar *) "", 1, Field::NONE, &empty_clex_str);
}


Field *Type_handler_null::make_conversion_table_field(MEM_ROOT *root,
                                                      TABLE *table,
                                                      uint metadata,
                                                      const Field *target)
                                                      const
{
  return new(root)
         Field_null(NULL, 0, Field::NONE, &empty_clex_str, target->charset());
}


Field *Type_handler_timestamp::make_conversion_table_field(MEM_ROOT *root,
                                                           TABLE *table,
                                                           uint metadata,
                                                           const Field *target)
                                                           const
{
  return new_Field_timestamp(root, NULL, (uchar *) "", 1,
                             Field::NONE, &empty_clex_str,
                             table->s, target->decimals());
}


Field *Type_handler_timestamp2::make_conversion_table_field(MEM_ROOT *root,
                                                            TABLE *table,
                                                            uint metadata,
                                                            const Field *target)
                                                            const
{
  return new(root)
         Field_timestampf(NULL, (uchar *) "", 1, Field::NONE,
                          &empty_clex_str, table->s, metadata);
}


Field *Type_handler_newdate::make_conversion_table_field(MEM_ROOT *root,
                                                         TABLE *table,
                                                         uint metadata,
                                                         const Field *target)
                                                         const
{
  return new(root)
         Field_newdate(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str);
}


Field *Type_handler_date::make_conversion_table_field(MEM_ROOT *root,
                                                      TABLE *table,
                                                      uint metadata,
                                                      const Field *target)
                                                      const
{
  return new(root)
         Field_date(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str);
}


Field *Type_handler_time::make_conversion_table_field(MEM_ROOT *root,
                                                      TABLE *table,
                                                      uint metadata,
                                                      const Field *target)
                                                      const
{
  return new_Field_time(root, NULL, (uchar *) "", 1,
                        Field::NONE, &empty_clex_str, target->decimals());
}


Field *Type_handler_time2::make_conversion_table_field(MEM_ROOT *root,
                                                       TABLE *table,
                                                       uint metadata,
                                                       const Field *target)
                                                       const
{
  return new(root)
         Field_timef(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str, metadata);
}


Field *Type_handler_datetime::make_conversion_table_field(MEM_ROOT *root,
                                                          TABLE *table,
                                                          uint metadata,
                                                          const Field *target)
                                                          const
{
  return new_Field_datetime(root, NULL, (uchar *) "", 1,
                            Field::NONE, &empty_clex_str, target->decimals());
}


Field *Type_handler_datetime2::make_conversion_table_field(MEM_ROOT *root,
                                                           TABLE *table,
                                                           uint metadata,
                                                           const Field *target)
                                                           const
{
  return new(root)
         Field_datetimef(NULL, (uchar *) "", 1,
                         Field::NONE, &empty_clex_str, metadata);
}


Field *Type_handler_bit::make_conversion_table_field(MEM_ROOT *root,
                                                     TABLE *table,
                                                     uint metadata,
                                                     const Field *target)
                                                     const
{
  DBUG_ASSERT((metadata & 0xff) <= 7);
  uint32 max_length= 8 * (metadata >> 8U) + (metadata & 0x00ff);
  return new(root)
         Field_bit_as_char(NULL, max_length, (uchar *) "", 1,
                           Field::NONE, &empty_clex_str);
}


Field *Type_handler_string::make_conversion_table_field(MEM_ROOT *root,
                                                        TABLE *table,
                                                        uint metadata,
                                                        const Field *target)
                                                        const
{
  /* This is taken from Field_string::unpack. */
  uint32 max_length= (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff);
  return new(root)
         Field_string(NULL, max_length, (uchar *) "", 1,
                      Field::NONE, &empty_clex_str, target->charset());
}


Field *Type_handler_varchar::make_conversion_table_field(MEM_ROOT *root,
                                                         TABLE *table,
                                                         uint metadata,
                                                         const Field *target)
                                                         const
{
  DBUG_ASSERT(HA_VARCHAR_PACKLENGTH(metadata) <= MAX_FIELD_VARCHARLENGTH);
  return new(root)
         Field_varstring(NULL, metadata, HA_VARCHAR_PACKLENGTH(metadata),
                         (uchar *) "", 1, Field::NONE, &empty_clex_str,
                         table->s, target->charset());
}


Field *Type_handler_varchar_compressed::make_conversion_table_field(
                                                         MEM_ROOT *root, 
                                                         TABLE *table,
                                                         uint metadata,
                                                         const Field *target)
                                                         const
{
  return new(root)
         Field_varstring_compressed(NULL, metadata,
                                    HA_VARCHAR_PACKLENGTH(metadata),
                                    (uchar *) "", 1, Field::NONE,
                                    &empty_clex_str,
                                    table->s, target->charset(),
                                    zlib_compression_method);
}



Field *Type_handler_blob_compressed::make_conversion_table_field(
                                                      MEM_ROOT *root, 
                                                      TABLE *table,
                                                      uint metadata,
                                                      const Field *target)
                                                      const
{
  uint pack_length= metadata & 0x00ff;
  if (pack_length < 1 || pack_length > 4)
    return NULL; // Broken binary log?
  return new(root)
         Field_blob_compressed(NULL, (uchar *) "", 1, Field::NONE,
                               &empty_clex_str,
                               table->s, pack_length, target->charset(),
                               zlib_compression_method);
}


Field *Type_handler_enum::make_conversion_table_field(MEM_ROOT *root,
                                                      TABLE *table,
                                                      uint metadata,
                                                      const Field *target)
                                                      const
{
  DBUG_ASSERT(target->type() == MYSQL_TYPE_STRING);
  DBUG_ASSERT(target->real_type() == MYSQL_TYPE_ENUM);
  return new(root)
         Field_enum(NULL, target->field_length,
                    (uchar *) "", 1, Field::NONE, &empty_clex_str,
                    metadata & 0x00ff/*pack_length()*/,
                    ((const Field_enum*) target)->typelib, target->charset());
}


Field *Type_handler_set::make_conversion_table_field(MEM_ROOT *root,
                                                     TABLE *table,
                                                     uint metadata,
                                                     const Field *target)
                                                     const
{
  DBUG_ASSERT(target->type() == MYSQL_TYPE_STRING);
  DBUG_ASSERT(target->real_type() == MYSQL_TYPE_SET);
  return new(root)
         Field_set(NULL, target->field_length,
                   (uchar *) "", 1, Field::NONE, &empty_clex_str,
                   metadata & 0x00ff/*pack_length()*/,
                   ((const Field_enum*) target)->typelib, target->charset());
}


Field *Type_handler_enum::make_schema_field(MEM_ROOT *root, TABLE *table,
                                            const Record_addr &addr,
                                            const ST_FIELD_INFO &def) const
{
  LEX_CSTRING name= def.name();
  const Typelib *typelib= def.typelib();
  DBUG_ASSERT(typelib);
  /*
    Assume I_S columns don't have non-ASCII characters in names.
    If we eventually want to, Typelib::max_char_length() must be implemented.
  */
  return new (root)
         Field_enum(addr.ptr(), (uint32) typelib->max_octet_length(),
                    addr.null_ptr(), addr.null_bit(),
                    Field::NONE, &name,
                    get_enum_pack_length(typelib->count),
                    typelib, system_charset_info);

}


/*************************************************************************/

bool Type_handler::
       Column_definition_validate_check_constraint(THD *thd,
                                                   Column_definition * c) const
{
  return c->validate_check_constraint(thd);
}


/*************************************************************************/

bool
Type_handler::Column_definition_set_attributes(THD *thd,
                                               Column_definition *def,
                                               const Lex_field_type_st &attr,
                                               CHARSET_INFO *cs,
                                               column_definition_type_t type)
                                               const
{
  def->charset= cs;
  def->set_length_and_dec(attr);
  return false;
}


/*
  In sql_mode=ORACLE, real size of VARCHAR and CHAR with no length
  in SP parameters is fixed at runtime with the length of real args.
  Let's translate VARCHAR to VARCHAR(4000) for return value.

  Since Oracle 9, maximum size for VARCHAR in PL/SQL is 32767.

  In MariaDB the limit for VARCHAR is 65535 bytes.
  We could translate VARCHAR with no length to VARCHAR(65535), but
  it would mean that for multi-byte character sets we'd have to translate
  VARCHAR to MEDIUMTEXT, to guarantee 65535 characters.

  Also we could translate VARCHAR to VARCHAR(16383), where 16383 is
  the maximum possible length in characters in case of mbmaxlen=4
  (e.g. utf32, utf16, utf8mb4). However, we'll have character sets with
  mbmaxlen=5 soon (e.g. gb18030).
*/

bool
Type_handler_string::Column_definition_set_attributes(
                                                 THD *thd,
                                                 Column_definition *def,
                                                 const Lex_field_type_st &attr,
                                                 CHARSET_INFO *cs,
                                                 column_definition_type_t type)
                                                 const
{
  Type_handler::Column_definition_set_attributes(thd, def, attr, cs, type);
  if (attr.length())
    return false;
  switch (type) {
  case COLUMN_DEFINITION_ROUTINE_PARAM:
  case COLUMN_DEFINITION_FUNCTION_RETURN:
    if (thd->variables.sql_mode & MODE_ORACLE)
    {
      // See Type_handler_varchar::Column_definition_set_attributes()
      def->length= def->decimals= 2000;
      def->set_handler(&type_handler_varchar);
      return false;
    }
    break;
  case COLUMN_DEFINITION_ROUTINE_LOCAL:
  case COLUMN_DEFINITION_TABLE_FIELD:
    break;
  }
  def->length= 1;
  return false;
}


bool
Type_handler_varchar::Column_definition_set_attributes(
                                                 THD *thd,
                                                 Column_definition *def,
                                                 const Lex_field_type_st &attr,
                                                 CHARSET_INFO *cs,
                                                 column_definition_type_t type)
                                                 const
{
  Type_handler::Column_definition_set_attributes(thd, def, attr, cs, type);
  if (attr.length())
    return false;
  switch (type) {
  case COLUMN_DEFINITION_ROUTINE_PARAM:
  case COLUMN_DEFINITION_FUNCTION_RETURN:
    if (thd->variables.sql_mode & MODE_ORACLE)
    {
      /*
        Type_handler_varchar::adjust_spparam_type() tests "decimals"
        to detect if the formal parameter length needs to be adjusted to
        the actual parameter length. Non-zero decimals means that the length
        was set implicitly to the default value and needs to be adjusted.
      */
      def->length= def->decimals= 4000;
      return false;
    }
    break;
  case COLUMN_DEFINITION_ROUTINE_LOCAL:
  case COLUMN_DEFINITION_TABLE_FIELD:
    break;
  }
  thd->parse_error();
  return true;
}


/*************************************************************************/
bool Type_handler_null::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return false;
}

bool Type_handler_tiny::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return def->fix_attributes_int(MAX_TINYINT_WIDTH + def->sign_length());
}

bool Type_handler_short::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return def->fix_attributes_int(MAX_SMALLINT_WIDTH + def->sign_length());
}

bool Type_handler_int24::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return def->fix_attributes_int(MAX_MEDIUMINT_WIDTH + def->sign_length());
}

bool Type_handler_long::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return def->fix_attributes_int(MAX_INT_WIDTH + def->sign_length());
}

bool Type_handler_longlong::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return def->fix_attributes_int(MAX_BIGINT_WIDTH/*no sign_length() added*/);
}

bool Type_handler_newdecimal::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return def->fix_attributes_decimal();
}

bool Type_handler_olddecimal::
       Column_definition_fix_attributes(Column_definition *def) const
{
  DBUG_ASSERT(0); // Obsolete
  return true;
}

bool Type_handler_var_string::
       Column_definition_fix_attributes(Column_definition *def) const
{
  DBUG_ASSERT(0); // Obsolete
  return true;
}

bool Type_handler_varchar::
       Column_definition_fix_attributes(Column_definition *def) const
{
  /*
    Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
    if they don't have a default value
  */
  return def->check_length(ER_TOO_BIG_DISPLAYWIDTH, MAX_FIELD_BLOBLENGTH);
}

bool Type_handler_string::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return def->check_length(ER_TOO_BIG_FIELDLENGTH, MAX_FIELD_CHARLENGTH);
}

bool Type_handler_blob_common::
       Column_definition_fix_attributes(Column_definition *def) const
{
  def->flags|= BLOB_FLAG;
  return def->check_length(ER_TOO_BIG_DISPLAYWIDTH, MAX_FIELD_BLOBLENGTH);
}


bool Type_handler_year::
       Column_definition_fix_attributes(Column_definition *def) const
{
  if (!def->length || def->length != 2)
    def->length= 4; // Default length
  def->flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
  return false;
}

bool Type_handler_float::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return def->fix_attributes_real(MAX_FLOAT_STR_LENGTH);
}


bool Type_handler_double::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return def->fix_attributes_real(DBL_DIG + 7);
}

bool Type_handler_timestamp_common::
       Column_definition_fix_attributes(Column_definition *def) const
{
  def->flags|= UNSIGNED_FLAG;
  return def->fix_attributes_temporal_with_time(MAX_DATETIME_WIDTH);
}

bool Type_handler_date_common::
       Column_definition_fix_attributes(Column_definition *def) const
{
  // We don't support creation of MYSQL_TYPE_DATE anymore
  def->set_handler(&type_handler_newdate);
  def->length= MAX_DATE_WIDTH;
  return false;
}

bool Type_handler_time_common::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return def->fix_attributes_temporal_with_time(MIN_TIME_WIDTH);
}

bool Type_handler_datetime_common::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return def->fix_attributes_temporal_with_time(MAX_DATETIME_WIDTH);
}

bool Type_handler_set::
       Column_definition_fix_attributes(Column_definition *def) const
{
  def->pack_length= get_set_pack_length(def->interval_list.elements);
  return false;
}

bool Type_handler_enum::
       Column_definition_fix_attributes(Column_definition *def) const
{
  def->pack_length= get_enum_pack_length(def->interval_list.elements);
  return false;
}

bool Type_handler_bit::
       Column_definition_fix_attributes(Column_definition *def) const
{
  return def->fix_attributes_bit();
}

/*************************************************************************/

void Type_handler_typelib::
       Column_definition_reuse_fix_attributes(THD *thd,
                                              Column_definition *def,
                                              const Field *field) const
{
  DBUG_ASSERT(def->flags & (ENUM_FLAG | SET_FLAG));
  def->interval= field->get_typelib();
}


void Type_handler_year::
       Column_definition_reuse_fix_attributes(THD *thd,
                                              Column_definition *def,
                                              const Field *field) const
{
  if (def->length != 4)
  {
    char buff[sizeof("YEAR()") + MY_INT64_NUM_DECIMAL_DIGITS + 1];
    my_snprintf(buff, sizeof(buff), "YEAR(%llu)", def->length);
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
                        ER_WARN_DEPRECATED_SYNTAX,
                        ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
                        buff, "YEAR(4)");
  }
}


void Type_handler_real_result::
       Column_definition_reuse_fix_attributes(THD *thd,
                                              Column_definition *def,
                                              const Field *field) const
{
  /*
    Floating points are stored with FLOATING_POINT_DECIMALS but internally
    in MariaDB used with NOT_FIXED_DEC, which is >= FLOATING_POINT_DECIMALS.
  */
  if (def->decimals >= FLOATING_POINT_DECIMALS)
    def->decimals= NOT_FIXED_DEC;
}


/*************************************************************************/

bool Type_handler::
       Column_definition_prepare_stage1(THD *thd,
                                        MEM_ROOT *mem_root,
                                        Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  def->create_length_to_internal_length_simple();
  return false;
}

bool Type_handler_null::
       Column_definition_prepare_stage1(THD *thd,
                                        MEM_ROOT *mem_root,
                                        Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  def->create_length_to_internal_length_null();
  return false;
}

bool Type_handler_row::
       Column_definition_prepare_stage1(THD *thd,
                                        MEM_ROOT *mem_root,
                                        Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  def->create_length_to_internal_length_null();
  return false;
}

bool Type_handler_newdecimal::
       Column_definition_prepare_stage1(THD *thd,
                                        MEM_ROOT *mem_root,
                                        Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  def->create_length_to_internal_length_newdecimal();
  return false;
}

bool Type_handler_bit::
       Column_definition_prepare_stage1(THD *thd,
                                        MEM_ROOT *mem_root,
                                        Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  return def->prepare_stage1_bit(thd, mem_root, file, table_flags);
}

bool Type_handler_typelib::
       Column_definition_prepare_stage1(THD *thd,
                                        MEM_ROOT *mem_root,
                                        Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  return def->prepare_stage1_typelib(thd, mem_root, file, table_flags);
}


bool Type_handler_string_result::
       Column_definition_prepare_stage1(THD *thd,
                                        MEM_ROOT *mem_root,
                                        Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  return def->prepare_stage1_string(thd, mem_root, file, table_flags);
}


/*************************************************************************/

bool Type_handler::
       Column_definition_redefine_stage1(Column_definition *def,
                                         const Column_definition *dup,
                                         const handler *file,
                                         const Schema_specification_st *schema)
                                         const
{
  def->redefine_stage1_common(dup, file, schema);
  def->create_length_to_internal_length_simple();
  return false;
}


bool Type_handler_null::
       Column_definition_redefine_stage1(Column_definition *def,
                                         const Column_definition *dup,
                                         const handler *file,
                                         const Schema_specification_st *schema)
                                         const
{
  def->redefine_stage1_common(dup, file, schema);
  def->create_length_to_internal_length_null();
  return false;
}


bool Type_handler_newdecimal::
       Column_definition_redefine_stage1(Column_definition *def,
                                         const Column_definition *dup,
                                         const handler *file,
                                         const Schema_specification_st *schema)
                                         const
{
  def->redefine_stage1_common(dup, file, schema);
  def->create_length_to_internal_length_newdecimal();
  return false;
}


bool Type_handler_string_result::
       Column_definition_redefine_stage1(Column_definition *def,
                                         const Column_definition *dup,
                                         const handler *file,
                                         const Schema_specification_st *schema)
                                         const
{
  def->redefine_stage1_common(dup, file, schema);
  def->set_compression_method(dup->compression_method());
  def->create_length_to_internal_length_string();
  return false;
}


bool Type_handler_typelib::
       Column_definition_redefine_stage1(Column_definition *def,
                                         const Column_definition *dup,
                                         const handler *file,
                                         const Schema_specification_st *schema)
                                         const
{
  def->redefine_stage1_common(dup, file, schema);
  def->create_length_to_internal_length_typelib();
  return false;
}


bool Type_handler_bit::
       Column_definition_redefine_stage1(Column_definition *def,
                                         const Column_definition *dup,
                                         const handler *file,
                                         const Schema_specification_st *schema)
                                         const
{
  def->redefine_stage1_common(dup, file, schema);
  /*
    If we are replacing a field with a BIT field, we need
    to initialize pack_flag.
  */
  def->pack_flag= FIELDFLAG_NUMBER;
  if (!(file->ha_table_flags() & HA_CAN_BIT_FIELD))
    def->pack_flag|= FIELDFLAG_TREAT_BIT_AS_CHAR;
  def->create_length_to_internal_length_bit();
  return false;
}


/*************************************************************************/

bool Type_handler::
       Column_definition_prepare_stage2_legacy(Column_definition *def,
                                               enum_field_types type) const
{
  def->pack_flag= f_settype((uint) type);
  return false;
}

bool Type_handler::
       Column_definition_prepare_stage2_legacy_num(Column_definition *def,
                                                   enum_field_types type) const
{
  def->pack_flag= def->pack_flag_numeric() | f_settype((uint) type);
  return false;
}

bool Type_handler::
       Column_definition_prepare_stage2_legacy_real(Column_definition *def,
                                                    enum_field_types type) const
{
  uint dec= def->decimals;
  /*
    User specified FLOAT() or DOUBLE() without precision. Change to
    FLOATING_POINT_DECIMALS to keep things compatible with earlier MariaDB
    versions.
  */
  if (dec >= FLOATING_POINT_DECIMALS)
    dec= FLOATING_POINT_DECIMALS;
  def->decimals= dec;
  def->pack_flag= def->pack_flag_numeric() | f_settype((uint) type);
  return false;
}

bool Type_handler_newdecimal::
       Column_definition_prepare_stage2(Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  def->pack_flag= def->pack_flag_numeric();
  return false;
}

bool Type_handler_blob_common::
       Column_definition_prepare_stage2(Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  return def->prepare_stage2_blob(file, table_flags, FIELDFLAG_BLOB);
}

bool Type_handler_varchar::
       Column_definition_prepare_stage2(Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  return def->prepare_stage2_varchar(table_flags);
}

bool Type_handler_string::
       Column_definition_prepare_stage2(Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  def->pack_flag= (def->charset->state & MY_CS_BINSORT) ? FIELDFLAG_BINARY : 0;
  return false;
}

bool Type_handler_enum::
       Column_definition_prepare_stage2(Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  uint dummy;
  return def->prepare_stage2_typelib("ENUM", FIELDFLAG_INTERVAL, &dummy);
}

bool Type_handler_set::
       Column_definition_prepare_stage2(Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  uint dup_count;
  if (def->prepare_stage2_typelib("SET", FIELDFLAG_BITFIELD, &dup_count))
    return true;
  /* Check that count of unique members is not more then 64 */
  if (def->interval->count - dup_count > sizeof(longlong)*8)
  {
     my_error(ER_TOO_BIG_SET, MYF(0), def->field_name.str);
     return true;
  }
  return false;
}

bool Type_handler_bit::
       Column_definition_prepare_stage2(Column_definition *def,
                                        handler *file,
                                        ulonglong table_flags) const
{
  /* 
    We have sql_field->pack_flag already set here, see
    mysql_prepare_create_table().
  */
  return false;
}


/*************************************************************************/
bool Type_handler::Key_part_spec_init_primary(Key_part_spec *part,
                                              const Column_definition &def,
                                              const handler *file) const
{
  part->length*= def.charset->mbmaxlen;
  return false;
}


bool Type_handler::Key_part_spec_init_unique(Key_part_spec *part,
                                             const Column_definition &def,
                                             const handler *file,
                                             bool *has_field_needed) const
{
  part->length*= def.charset->mbmaxlen;
  return false;
}


bool Type_handler::Key_part_spec_init_multiple(Key_part_spec *part,
                                               const Column_definition &def,
                                               const handler *file) const
{
  part->length*= def.charset->mbmaxlen;
  return false;
}


bool Type_handler::Key_part_spec_init_foreign(Key_part_spec *part,
                                              const Column_definition &def,
                                              const handler *file) const
{
  part->length*= def.charset->mbmaxlen;
  return false;
}


bool Type_handler::Key_part_spec_init_spatial(Key_part_spec *part,
                                              const Column_definition &def)
                                              const
{
  my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
  return true;
}


bool Type_handler_blob_common::Key_part_spec_init_primary(Key_part_spec *part,
                                              const Column_definition &def,
                                              const handler *file) const
{
  part->length*= def.charset->mbmaxlen;
  return part->check_primary_key_for_blob(file);
}


bool Type_handler_blob_common::Key_part_spec_init_unique(Key_part_spec *part,
                                              const Column_definition &def,
                                              const handler *file,
                                              bool *hash_field_needed) const
{
  if (!(part->length*= def.charset->mbmaxlen))
    *hash_field_needed= true;
  return part->check_key_for_blob(file);
}


bool Type_handler_blob_common::Key_part_spec_init_multiple(Key_part_spec *part,
                                               const Column_definition &def,
                                               const handler *file) const
{
  part->length*= def.charset->mbmaxlen;
  return part->init_multiple_key_for_blob(file);
}


bool Type_handler_blob_common::Key_part_spec_init_foreign(Key_part_spec *part,
                                               const Column_definition &def,
                                               const handler *file) const
{
  part->length*= def.charset->mbmaxlen;
  return part->check_foreign_key_for_blob(file);
}



/*************************************************************************/

uint32 Type_handler_time::calc_pack_length(uint32 length) const
{
  return length > MIN_TIME_WIDTH ?
         hires_bytes(length - 1 - MIN_TIME_WIDTH) : 3;
}

uint32 Type_handler_time2::calc_pack_length(uint32 length) const
{
  return length > MIN_TIME_WIDTH ?
         my_time_binary_length(length - MIN_TIME_WIDTH - 1) : 3;
}

uint32 Type_handler_timestamp::calc_pack_length(uint32 length) const
{
  return length > MAX_DATETIME_WIDTH ?
         4 + sec_part_bytes(length - 1 - MAX_DATETIME_WIDTH) : 4;
}

uint32 Type_handler_timestamp2::calc_pack_length(uint32 length) const
{
  return length > MAX_DATETIME_WIDTH ?
         my_timestamp_binary_length(length - MAX_DATETIME_WIDTH - 1) : 4;
}

uint32 Type_handler_datetime::calc_pack_length(uint32 length) const
{
  return length > MAX_DATETIME_WIDTH ?
         hires_bytes(length - 1 - MAX_DATETIME_WIDTH) : 8;
}

uint32 Type_handler_datetime2::calc_pack_length(uint32 length) const
{
  return length > MAX_DATETIME_WIDTH ?
         my_datetime_binary_length(length - MAX_DATETIME_WIDTH - 1) : 5;
}

uint32 Type_handler_tiny_blob::calc_pack_length(uint32 length) const
{
  return 1 + portable_sizeof_char_ptr;
}

uint32 Type_handler_blob::calc_pack_length(uint32 length) const
{
  return 2 + portable_sizeof_char_ptr;
}

uint32 Type_handler_medium_blob::calc_pack_length(uint32 length) const
{
  return 3 + portable_sizeof_char_ptr;
}

uint32 Type_handler_long_blob::calc_pack_length(uint32 length) const
{
  return 4 + portable_sizeof_char_ptr;
}

uint32 Type_handler_newdecimal::calc_pack_length(uint32 length) const
{
  abort();  // This shouldn't happen
  return 0;
}

uint32 Type_handler_set::calc_pack_length(uint32 length) const
{
  abort();  // This shouldn't happen
  return 0;
}

uint32 Type_handler_enum::calc_pack_length(uint32 length) const
{
  abort();  // This shouldn't happen
  return 0;
}


/*************************************************************************/
uint Type_handler::calc_key_length(const Column_definition &def) const
{
  DBUG_ASSERT(def.pack_length == calc_pack_length((uint32) def.length));
  return def.pack_length;
}

uint Type_handler_bit::calc_key_length(const Column_definition &def) const
{
  if (f_bit_as_char(def.pack_flag))
    return def.pack_length;
  /* We need one extra byte to store the bits we save among the null bits */
  return def.pack_length + MY_TEST(def.length & 7);
}

uint Type_handler_newdecimal::calc_key_length(const Column_definition &def) const
{
  return def.pack_length;
}

uint
Type_handler_string_result::calc_key_length(const Column_definition &def) const
{
  return (uint) def.length;
}

uint Type_handler_enum::calc_key_length(const Column_definition &def) const
{
  DBUG_ASSERT(def.interval);
  return get_enum_pack_length(def.interval->count);
}

uint Type_handler_set::calc_key_length(const Column_definition &def) const
{
  DBUG_ASSERT(def.interval);
  return get_set_pack_length(def.interval->count);
}

uint Type_handler_blob_common::calc_key_length(const Column_definition &def) const
{
  return 0;
}

/*************************************************************************/
Field *Type_handler::make_and_init_table_field(MEM_ROOT *root,
                                               const LEX_CSTRING *name,
                                               const Record_addr &addr,
                                               const Type_all_attributes &attr,
                                               TABLE *table) const
{
  Field *field= make_table_field(root, name, addr, attr, table->s);
  if (field)
    field->init(table);
  return field;
}


Field *Type_handler_int_result::make_table_field(MEM_ROOT *root,
                                           const LEX_CSTRING *name,
                                           const Record_addr &addr,
                                           const Type_all_attributes &attr,
                                           TABLE_SHARE *share) const
{
  DBUG_ASSERT(is_unsigned() == attr.unsigned_flag);
  Column_definition_attributes dattr(attr);
  return make_table_field_from_def(share, root, name, addr,
                                   Bit_addr(), &dattr, 0);
}


Field *Type_handler_vers_trx_id::make_table_field(MEM_ROOT *root,
                                               const LEX_CSTRING *name,
                                               const Record_addr &addr,
                                               const Type_all_attributes &attr,
                                               TABLE_SHARE *share) const
{
  DBUG_ASSERT(is_unsigned() == attr.unsigned_flag);
  return new (root)
         Field_vers_trx_id(addr.ptr(), attr.max_char_length(),
                        addr.null_ptr(), addr.null_bit(),
                        Field::NONE, name,
                        0/*zerofill*/, attr.unsigned_flag);
}


Field *
Type_handler_real_result::make_table_field(MEM_ROOT *root,
                                           const LEX_CSTRING *name,
                                           const Record_addr &addr,
                                           const Type_all_attributes &attr,
                                           TABLE_SHARE *share) const
{
  Column_definition_attributes dattr(attr);
  return make_table_field_from_def(share, root, name, addr,
                                   Bit_addr(), &dattr, 0);
}


Field *
Type_handler_olddecimal::make_table_field(MEM_ROOT *root,
                                          const LEX_CSTRING *name,
                                          const Record_addr &addr,
                                          const Type_all_attributes &attr,
                                          TABLE_SHARE *share) const
{
  /*
    Currently make_table_field() is used for Item purpose only.
    On Item level we have type_handler_newdecimal only.
    For now we have DBUG_ASSERT(0).
    It will be removed when we reuse Type_handler::make_table_field()
    in make_field() in field.cc, to open old tables with old decimal.
  */
  DBUG_ASSERT(0);
  Column_definition_attributes dattr(attr);
  return make_table_field_from_def(share, root, name, addr,
                                   Bit_addr(), &dattr, 0);
}


Field *
Type_handler_newdecimal::make_table_field(MEM_ROOT *root,
                                          const LEX_CSTRING *name,
                                          const Record_addr &addr,
                                          const Type_all_attributes &attr,
                                          TABLE_SHARE *share) const
{
  uint8 dec= (uint8) attr.decimals;
  uint8 intg= (uint8) (attr.decimal_precision() - dec);
  uint32 len= attr.max_char_length();

  /*
    Trying to put too many digits overall in a DECIMAL(prec,dec)
    will always throw a warning. We must limit dec to
    DECIMAL_MAX_SCALE however to prevent an assert() later.
  */

  if (dec > 0)
  {
    signed int overflow;

    dec= MY_MIN(dec, DECIMAL_MAX_SCALE);

    /*
      If the value still overflows the field with the corrected dec,
      we'll throw out decimals rather than integers. This is still
      bad and of course throws a truncation warning.
      +1: for decimal point
      */

    const int required_length=
      my_decimal_precision_to_length(intg + dec, dec, attr.unsigned_flag);

    overflow= required_length - len;

    if (overflow > 0)
      dec= MY_MAX(0, dec - overflow);            // too long, discard fract
    else
      /* Corrected value fits. */
      len= required_length;
  }
  return new (root)
         Field_new_decimal(addr.ptr(), len, addr.null_ptr(), addr.null_bit(),
                           Field::NONE, name,
                           dec, 0/*zerofill*/, attr.unsigned_flag);
}


Field *Type_handler_null::make_table_field(MEM_ROOT *root,
                                           const LEX_CSTRING *name,
                                           const Record_addr &addr,
                                           const Type_all_attributes &attr,
                                           TABLE_SHARE *share) const

{
  return new (root)
         Field_null(addr.ptr(), attr.max_length,
                    Field::NONE, name, attr.collation.collation);
}


Field *Type_handler_timestamp::make_table_field(MEM_ROOT *root,
                                                const LEX_CSTRING *name,
                                                const Record_addr &addr,
                                                const Type_all_attributes &attr,
                                                TABLE_SHARE *share) const

{
  return new_Field_timestamp(root,
                             addr.ptr(), addr.null_ptr(), addr.null_bit(),
                             Field::NONE, name, share, attr.decimals);
}


Field *Type_handler_timestamp2::make_table_field(MEM_ROOT *root,
                                                 const LEX_CSTRING *name,
                                                 const Record_addr &addr,
                                                 const Type_all_attributes &attr,
                                                 TABLE_SHARE *share) const

{
  /*
    Will be changed to "new Field_timestampf" when we reuse
    make_table_field() for make_field() purposes in field.cc.
  */
  return new_Field_timestamp(root,
                             addr.ptr(), addr.null_ptr(), addr.null_bit(),
                             Field::NONE, name, share, attr.decimals);
}


Field *Type_handler_newdate::make_table_field(MEM_ROOT *root,
                                              const LEX_CSTRING *name,
                                              const Record_addr &addr,
                                              const Type_all_attributes &attr,
                                              TABLE_SHARE *share) const

{
  return new (root)
         Field_newdate(addr.ptr(), addr.null_ptr(), addr.null_bit(),
                       Field::NONE, name);
}


Field *Type_handler_date::make_table_field(MEM_ROOT *root,
                                           const LEX_CSTRING *name,
                                           const Record_addr &addr,
                                           const Type_all_attributes &attr,
                                           TABLE_SHARE *share) const

{
  /*
    DBUG_ASSERT will be removed when we reuse make_table_field()
    for make_field() in field.cc
  */
  DBUG_ASSERT(0);
  return new (root)
         Field_date(addr.ptr(), addr.null_ptr(), addr.null_bit(),
                    Field::NONE, name);
}


Field *Type_handler_time::make_table_field(MEM_ROOT *root,
                                           const LEX_CSTRING *name,
                                           const Record_addr &addr,
                                           const Type_all_attributes &attr,
                                           TABLE_SHARE *share) const

{
  return new_Field_time(root,
                        addr.ptr(), addr.null_ptr(), addr.null_bit(),
                        Field::NONE, name, attr.decimals);
}


Field *Type_handler_time2::make_table_field(MEM_ROOT *root,
                                            const LEX_CSTRING *name,
                                            const Record_addr &addr,
                                            const Type_all_attributes &attr,
                                            TABLE_SHARE *share) const


{
  /*
    Will be changed to "new Field_timef" when we reuse
    make_table_field() for make_field() purposes in field.cc.
  */
  return new_Field_time(root,
                        addr.ptr(), addr.null_ptr(), addr.null_bit(),
                        Field::NONE, name, attr.decimals);
}


Field *Type_handler_datetime::make_table_field(MEM_ROOT *root,
                                               const LEX_CSTRING *name,
                                               const Record_addr &addr,
                                               const Type_all_attributes &attr,
                                               TABLE_SHARE *share) const

{
  return new_Field_datetime(root,
                            addr.ptr(), addr.null_ptr(), addr.null_bit(),
                            Field::NONE, name, attr.decimals);
}


Field *Type_handler_datetime2::make_table_field(MEM_ROOT *root,
                                                const LEX_CSTRING *name,
                                                const Record_addr &addr,
                                                const Type_all_attributes &attr,
                                                TABLE_SHARE *share) const
{
  /*
    Will be changed to "new Field_datetimef" when we reuse
    make_table_field() for make_field() purposes in field.cc.
  */
  return new_Field_datetime(root,
                            addr.ptr(), addr.null_ptr(), addr.null_bit(),
                            Field::NONE, name, attr.decimals);
}


Field *Type_handler_bit::make_table_field(MEM_ROOT *root,
                                          const LEX_CSTRING *name,
                                          const Record_addr &addr,
                                          const Type_all_attributes &attr,
                                          TABLE_SHARE *share) const

{
  return new (root)
         Field_bit_as_char(addr.ptr(), attr.max_length,
                           addr.null_ptr(), addr.null_bit(),
                           Field::NONE, name);
}


Field *Type_handler_string::make_table_field(MEM_ROOT *root,
                                             const LEX_CSTRING *name,
                                             const Record_addr &addr,
                                             const Type_all_attributes &attr,
                                             TABLE_SHARE *share) const

{
  return new (root)
         Field_string(addr.ptr(), attr.max_length,
                      addr.null_ptr(), addr.null_bit(),
                      Field::NONE, name, attr.collation);
}


Field *Type_handler_varchar::make_table_field(MEM_ROOT *root,
                                              const LEX_CSTRING *name,
                                              const Record_addr &addr,
                                              const Type_all_attributes &attr,
                                              TABLE_SHARE *share) const

{
  DBUG_ASSERT(HA_VARCHAR_PACKLENGTH(attr.max_length) <=
              MAX_FIELD_VARCHARLENGTH);
  return new (root)
         Field_varstring(addr.ptr(), attr.max_length,
                         HA_VARCHAR_PACKLENGTH(attr.max_length),
                         addr.null_ptr(), addr.null_bit(),
                         Field::NONE, name,
                         share, attr.collation);
}


Field *Type_handler_tiny_blob::make_table_field(MEM_ROOT *root,
                                                const LEX_CSTRING *name,
                                                const Record_addr &addr,
                                                const Type_all_attributes &attr,
                                                TABLE_SHARE *share) const

{
  return new (root)
         Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
                    Field::NONE, name, share,
                    1, attr.collation);
}


Field *Type_handler_blob::make_table_field(MEM_ROOT *root,
                                           const LEX_CSTRING *name,
                                           const Record_addr &addr,
                                           const Type_all_attributes &attr,
                                           TABLE_SHARE *share) const

{
  return new (root)
         Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
                    Field::NONE, name, share,
                    2, attr.collation);
}


Field *
Type_handler_medium_blob::make_table_field(MEM_ROOT *root,
                                           const LEX_CSTRING *name,
                                           const Record_addr &addr,
                                           const Type_all_attributes &attr,
                                           TABLE_SHARE *share) const

{
  return new (root)
         Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
                    Field::NONE, name, share,
                    3, attr.collation);
}


Field *Type_handler_long_blob::make_table_field(MEM_ROOT *root,
                                                const LEX_CSTRING *name,
                                                const Record_addr &addr,
                                                const Type_all_attributes &attr,
                                                TABLE_SHARE *share) const

{
  return new (root)
         Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
                    Field::NONE, name, share,
                    4, attr.collation);
}


Field *Type_handler_enum::make_table_field(MEM_ROOT *root,
                                           const LEX_CSTRING *name,
                                           const Record_addr &addr,
                                           const Type_all_attributes &attr,
                                           TABLE_SHARE *share) const
{
  const TYPELIB *typelib= attr.get_typelib();
  DBUG_ASSERT(typelib);
  return new (root)
         Field_enum(addr.ptr(), attr.max_length,
                    addr.null_ptr(), addr.null_bit(),
                    Field::NONE, name,
                    get_enum_pack_length(typelib->count), typelib,
                    attr.collation);
}


Field *Type_handler_set::make_table_field(MEM_ROOT *root,
                                          const LEX_CSTRING *name,
                                          const Record_addr &addr,
                                          const Type_all_attributes &attr,
                                          TABLE_SHARE *share) const

{
  const TYPELIB *typelib= attr.get_typelib();
  DBUG_ASSERT(typelib);
  return new (root)
         Field_set(addr.ptr(), attr.max_length,
                   addr.null_ptr(), addr.null_bit(),
                   Field::NONE, name,
                   get_enum_pack_length(typelib->count), typelib,
                   attr.collation);
}


/*************************************************************************/

Field *Type_handler_float::make_schema_field(MEM_ROOT *root, TABLE *table,
                                             const Record_addr &addr,
                                             const ST_FIELD_INFO &def) const
{
  LEX_CSTRING name= def.name();
  return new (root)
     Field_float(addr.ptr(), def.char_length(),
                  addr.null_ptr(), addr.null_bit(),
                  Field::NONE, &name,
                  (uint8) NOT_FIXED_DEC,
                  0/*zerofill*/, def.unsigned_flag());
}


Field *Type_handler_double::make_schema_field(MEM_ROOT *root, TABLE *table,
                                              const Record_addr &addr,
                                              const ST_FIELD_INFO &def) const
{
  LEX_CSTRING name= def.name();
  return new (root)
     Field_double(addr.ptr(), def.char_length(),
                  addr.null_ptr(), addr.null_bit(),
                  Field::NONE, &name,
                  (uint8) NOT_FIXED_DEC,
                  0/*zerofill*/, def.unsigned_flag());
}


Field *Type_handler_decimal_result::make_schema_field(MEM_ROOT *root,
                                                      TABLE *table,
                                                      const Record_addr &addr,
                                                      const ST_FIELD_INFO &def) const
{
  LEX_CSTRING name= def.name();
  uint dec= def.decimal_scale();
  uint prec= def.decimal_precision();
  DBUG_ASSERT(dec <= DECIMAL_MAX_SCALE);
  uint32 len= my_decimal_precision_to_length(prec, dec, def.unsigned_flag());
  return new (root)
     Field_new_decimal(addr.ptr(), len, addr.null_ptr(), addr.null_bit(),
                       Field::NONE, &name,
                       (uint8) dec, 0/*zerofill*/, def.unsigned_flag());
}


Field *Type_handler_blob_common::make_schema_field(MEM_ROOT *root, TABLE *table,
                                                   const Record_addr &addr,
                                                   const ST_FIELD_INFO &def) const
{
  LEX_CSTRING name= def.name();
  return new (root)
     Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
                Field::NONE, &name, table->s,
                length_bytes(),
                &my_charset_bin);
}


Field *Type_handler_varchar::make_schema_field(MEM_ROOT *root, TABLE *table,
                                               const Record_addr &addr,
                                               const ST_FIELD_INFO &def) const
{
  DBUG_ASSERT(def.char_length());
  LEX_CSTRING name= def.name();
  uint32 octet_length= (uint32) def.char_length() * 3;
  if (octet_length > MAX_FIELD_VARCHARLENGTH)
  {
    Field *field= new (root)
      Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE,
                 &name, table->s, 4, system_charset_info);
    if (field)
      field->field_length= octet_length;
    return field;
  }
  else
  {
    return new (root)
      Field_varstring(addr.ptr(), octet_length,
                      HA_VARCHAR_PACKLENGTH(octet_length),
                      addr.null_ptr(), addr.null_bit(),
                      Field::NONE, &name,
                      table->s, system_charset_info);
  }
}


Field *Type_handler_tiny::make_schema_field(MEM_ROOT *root, TABLE *table,
                                            const Record_addr &addr,
                                            const ST_FIELD_INFO &def) const
{
  LEX_CSTRING name= def.name();
  return new (root)
           Field_tiny(addr.ptr(), def.char_length(),
                      addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
                      0/*zerofill*/, def.unsigned_flag());
}


Field *Type_handler_short::make_schema_field(MEM_ROOT *root, TABLE *table,
                                             const Record_addr &addr,
                                             const ST_FIELD_INFO &def) const
{
  LEX_CSTRING name= def.name();
  return new (root)
           Field_short(addr.ptr(), def.char_length(),
                       addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
                       0/*zerofill*/, def.unsigned_flag());
}


Field *Type_handler_long::make_schema_field(MEM_ROOT *root, TABLE *table,
                                            const Record_addr &addr,
                                            const ST_FIELD_INFO &def) const
{
  LEX_CSTRING name= def.name();
  return new (root)
           Field_long(addr.ptr(), def.char_length(),
                      addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
                      0/*zerofill*/, def.unsigned_flag());
}


Field *Type_handler_longlong::make_schema_field(MEM_ROOT *root, TABLE *table,
                                                const Record_addr &addr,
                                                const ST_FIELD_INFO &def) const
{
  LEX_CSTRING name= def.name();
  return new (root)
           Field_longlong(addr.ptr(), def.char_length(),
                          addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
                          0/*zerofill*/, def.unsigned_flag());
}


Field *Type_handler_date_common::make_schema_field(MEM_ROOT *root, TABLE *table,
                                                   const Record_addr &addr,
                                                   const ST_FIELD_INFO &def) const
{
  LEX_CSTRING name= def.name();
  return new (root)
           Field_newdate(addr.ptr(), addr.null_ptr(), addr.null_bit(),
                         Field::NONE, &name);
}


Field *Type_handler_time_common::make_schema_field(MEM_ROOT *root, TABLE *table,
                                                   const Record_addr &addr,
                                                   const ST_FIELD_INFO &def) const
{
  LEX_CSTRING name= def.name();
  return new_Field_time(root,
                        addr.ptr(), addr.null_ptr(), addr.null_bit(),
                        Field::NONE, &name, def.fsp());
}


Field *Type_handler_datetime_common::make_schema_field(MEM_ROOT *root,
                                                       TABLE *table,
                                                       const Record_addr &addr,
                                                       const ST_FIELD_INFO &def) const
{
  LEX_CSTRING name= def.name();
  return new (root) Field_datetimef(addr.ptr(),
                                    addr.null_ptr(), addr.null_bit(),
                                    Field::NONE, &name, def.fsp());
}


/*************************************************************************/

/*
   If length is not specified for a varchar parameter, set length to the
   maximum length of the actual argument. Goals are:
   - avoid to allocate too much unused memory for m_var_table
   - allow length check inside the callee rather than during copy of
     returned values in output variables.
   - allow varchar parameter size greater than 4000
   Default length has been stored in "decimal" member during parse.
*/
bool Type_handler_varchar::adjust_spparam_type(Spvar_definition *def,
                                               Item *from) const
{
  if (def->decimals)
  {
    uint def_max_char_length= MAX_FIELD_VARCHARLENGTH / def->charset->mbmaxlen;
    uint arg_max_length= from->max_char_length();
    set_if_smaller(arg_max_length, def_max_char_length);
    def->length= arg_max_length > 0 ? arg_max_length : def->decimals;
    def->create_length_to_internal_length_string();
  }
  return false;
}

/*************************************************************************/

uint32 Type_handler_decimal_result::max_display_length(const Item *item) const
{
  return item->max_length;
}


uint32 Type_handler_temporal_result::max_display_length(const Item *item) const
{
  return item->max_length;
}

uint32 Type_handler_string_result::max_display_length(const Item *item) const
{
  return item->max_length;
}


uint32 Type_handler_year::max_display_length(const Item *item) const
{
  return item->max_length;
}


uint32 Type_handler_bit::max_display_length(const Item *item) const
{
  return item->max_length;
}

/*************************************************************************/

uint32 
Type_handler_decimal_result::Item_decimal_notation_int_digits(const Item *item)
                                                              const
{
  return item->decimal_int_part();
}


uint32 
Type_handler_temporal_result::Item_decimal_notation_int_digits(const Item *item)
                                                               const
{
  return item->decimal_int_part();
}


uint32 
Type_handler_bit::Item_decimal_notation_int_digits(const Item *item)
                                                              const
{
  return Bit_decimal_notation_int_digits_by_nbits(item->max_length);
}


uint32
Type_handler_general_purpose_int::Item_decimal_notation_int_digits(
                                                   const Item *item) const
{
  return type_limits_int()->precision();
}

/*************************************************************************/

/*
    Binary to Decimal digits ratio converges to log2(10) thus using 3 as
    a divisor.
*/
uint32
Type_handler_bit::Bit_decimal_notation_int_digits_by_nbits(uint nbits)
{
  DBUG_ASSERT(nbits > 0);
  DBUG_ASSERT(nbits <= 64);
  set_if_smaller(nbits, 64); // Safety
  static uint ndigits[65]=
  {0,
   1,1,1,2,2,2,3,3,         // 1..8 bits
   3,4,4,4,4,5,5,5,         // 9..16 bits
   6,6,6,7,7,7,7,8,         // 17..24 bits
   8,8,9,9,9,10,10,10,      // 25..32 bits
   10,11,11,11,12,12,12,13, // 33..40 bits
   13,13,13,14,14,14,15,15, // 41..48 bits
   15,16,16,16,16,17,17,17, // 49..56 bits
   18,18,18,19,19,19,19,20  // 57..64 bits
  };
  return ndigits[nbits];
}

/*************************************************************************/

void Type_handler_row::Item_update_null_value(Item *item) const
{
  DBUG_ASSERT(0);
  item->null_value= true;
}


void Type_handler_time_common::Item_update_null_value(Item *item) const
{
  MYSQL_TIME ltime;
  THD *thd= current_thd;
  (void) item->get_date(thd, &ltime, Time::Options(TIME_TIME_ONLY, thd));
}


void Type_handler_temporal_with_date::Item_update_null_value(Item *item) const
{
  MYSQL_TIME ltime;
  THD *thd= current_thd;
  (void) item->get_date(thd, &ltime, Datetime::Options(thd));
}

bool
Type_handler_timestamp_common::
Column_definition_set_attributes(THD *thd,
                                 Column_definition *def,
                                 const Lex_field_type_st &attr,
                                 CHARSET_INFO *cs,
                                 column_definition_type_t type) const
{
  Type_handler::Column_definition_set_attributes(thd, def, attr, cs, type);
  if (!opt_explicit_defaults_for_timestamp)
    def->flags|= NOT_NULL_FLAG;
  return false;
}

void Type_handler_string_result::Item_update_null_value(Item *item) const
{
  StringBuffer<MAX_FIELD_WIDTH> tmp;
  (void) item->val_str(&tmp);
}


void Type_handler_real_result::Item_update_null_value(Item *item) const
{
  (void) item->val_real();
}


void Type_handler_decimal_result::Item_update_null_value(Item *item) const
{
  my_decimal tmp;
  (void) item->val_decimal(&tmp);
}


void Type_handler_int_result::Item_update_null_value(Item *item) const
{
  (void) item->val_int();
}


void Type_handler_bool::Item_update_null_value(Item *item) const
{
  (void) item->val_bool();
}


/*************************************************************************/

int Type_handler_time_common::Item_save_in_field(Item *item, Field *field,
                                                 bool no_conversions) const
{
  return item->save_time_in_field(field, no_conversions);
}

int Type_handler_temporal_with_date::Item_save_in_field(Item *item,
                                                        Field *field,
                                                        bool no_conversions)
                                                        const
{
  return item->save_date_in_field(field, no_conversions);
}


int Type_handler_timestamp_common::Item_save_in_field(Item *item,
                                                      Field *field,
                                                      bool no_conversions)
                                                      const
{
  Timestamp_or_zero_datetime_native_null tmp(field->table->in_use, item, true);
  if (tmp.is_null())
    return set_field_to_null_with_conversions(field, no_conversions);
  return tmp.save_in_field(field, item->decimals);
}


int Type_handler_string_result::Item_save_in_field(Item *item, Field *field,
                                                   bool no_conversions) const
{
  return item->save_str_in_field(field, no_conversions);
}


int Type_handler_real_result::Item_save_in_field(Item *item, Field *field,
                                                 bool no_conversions) const
{
  return item->save_real_in_field(field, no_conversions);
}


int Type_handler_decimal_result::Item_save_in_field(Item *item, Field *field,
                                                    bool no_conversions) const
{
  return item->save_decimal_in_field(field, no_conversions);
}


int Type_handler_int_result::Item_save_in_field(Item *item, Field *field,
                                                bool no_conversions) const
{
  return item->save_int_in_field(field, no_conversions);
}


/***********************************************************************/

bool Type_handler_row::set_comparator_func(Arg_comparator *cmp) const
{
  return cmp->set_cmp_func_row();
}

bool Type_handler_int_result::set_comparator_func(Arg_comparator *cmp) const
{
  return cmp->set_cmp_func_int();
}

bool Type_handler_real_result::set_comparator_func(Arg_comparator *cmp) const
{
  return cmp->set_cmp_func_real();
}

bool Type_handler_decimal_result::set_comparator_func(Arg_comparator *cmp) const
{
  return cmp->set_cmp_func_decimal();
}

bool Type_handler_string_result::set_comparator_func(Arg_comparator *cmp) const
{
  return cmp->set_cmp_func_string();
}

bool Type_handler_time_common::set_comparator_func(Arg_comparator *cmp) const
{
  return cmp->set_cmp_func_time();
}

bool
Type_handler_temporal_with_date::set_comparator_func(Arg_comparator *cmp) const
{
  return cmp->set_cmp_func_datetime();
}

bool
Type_handler_timestamp_common::set_comparator_func(Arg_comparator *cmp) const
{
  return cmp->set_cmp_func_native();
}


/*************************************************************************/

bool Type_handler_temporal_result::
       can_change_cond_ref_to_const(Item_bool_func2 *target,
                                    Item *target_expr, Item *target_value,
                                    Item_bool_func2 *source,
                                    Item *source_expr, Item *source_const)
                                    const
{
  if (source->compare_type_handler()->cmp_type() != TIME_RESULT)
    return false;

  /*
    Can't rewrite:
      WHERE COALESCE(time_column)='00:00:00'
        AND COALESCE(time_column)=DATE'2015-09-11'
    to
      WHERE DATE'2015-09-11'='00:00:00'
        AND COALESCE(time_column)=DATE'2015-09-11'
    because the left part will erroneously try to parse '00:00:00'
    as DATE, not as TIME.

    TODO: It could still be rewritten to:
      WHERE DATE'2015-09-11'=TIME'00:00:00'
        AND COALESCE(time_column)=DATE'2015-09-11'
    i.e. we need to replace both target_expr and target_value
    at the same time. This is not supported yet.
  */
  return target_value->cmp_type() == TIME_RESULT;
}


bool Type_handler_string_result::
       can_change_cond_ref_to_const(Item_bool_func2 *target,
                                    Item *target_expr, Item *target_value,
                                    Item_bool_func2 *source,
                                    Item *source_expr, Item *source_const)
                                    const
{
  if (source->compare_type_handler()->cmp_type() != STRING_RESULT)
    return false;
  /*
    In this example:
      SET NAMES utf8 COLLATE utf8_german2_ci;
      DROP TABLE IF EXISTS t1;
      CREATE TABLE t1 (a CHAR(10) CHARACTER SET utf8);
      INSERT INTO t1 VALUES ('o-umlaut'),('oe');
      SELECT * FROM t1 WHERE a='oe' COLLATE utf8_german2_ci AND a='oe';

    the query should return only the row with 'oe'.
    It should not return 'o-umlaut', because 'o-umlaut' does not match
    the right part of the condition: a='oe'
    ('o-umlaut' is not equal to 'oe' in utf8mb3_general_ci,
     which is the collation of the field "a").

    If we change the right part from:
       ... AND a='oe'
    to
       ... AND 'oe' COLLATE utf8_german2_ci='oe'
    it will be evalulated to TRUE and removed from the condition,
    so the overall query will be simplified to:

      SELECT * FROM t1 WHERE a='oe' COLLATE utf8_german2_ci;

    which will erroneously start to return both 'oe' and 'o-umlaut'.
    So changing "expr" to "const" is not possible if the effective
    collations of "target" and "source" are not exactly the same.

    Note, the code before the fix for MDEV-7152 only checked that
    collations of "source_const" and "target_value" are the same.
    This was not enough, as the bug report demonstrated.
  */
  return
    target->compare_collation() == source->compare_collation() &&
    target_value->collation.collation == source_const->collation.collation;
}


bool Type_handler_numeric::
       can_change_cond_ref_to_const(Item_bool_func2 *target,
                                    Item *target_expr, Item *target_value,
                                    Item_bool_func2 *source,
                                    Item *source_expr, Item *source_const)
                                    const
{
  /*
   The collations of "target" and "source" do not make sense for numeric
   data types.
  */
  return target->compare_type_handler() == source->compare_type_handler();
}


/*************************************************************************/

Item_cache *
Type_handler_row::Item_get_cache(THD *thd, const Item *item) const
{
  return new (thd->mem_root) Item_cache_row(thd);
}

Item_cache *
Type_handler_int_result::Item_get_cache(THD *thd, const Item *item) const
{
  return new (thd->mem_root) Item_cache_int(thd, item->type_handler());
}

Item_cache *
Type_handler_year::Item_get_cache(THD *thd, const Item *item) const
{
  return new (thd->mem_root) Item_cache_year(thd, item->type_handler());
}

Item_cache *
Type_handler_double::Item_get_cache(THD *thd, const Item *item) const
{
  return new (thd->mem_root) Item_cache_double(thd);
}

Item_cache *
Type_handler_float::Item_get_cache(THD *thd, const Item *item) const
{
  return new (thd->mem_root) Item_cache_float(thd);
}

Item_cache *
Type_handler_decimal_result::Item_get_cache(THD *thd, const Item *item) const
{
  return new (thd->mem_root) Item_cache_decimal(thd);
}

Item_cache *
Type_handler_string_result::Item_get_cache(THD *thd, const Item *item) const
{
  return new (thd->mem_root) Item_cache_str(thd, item);
}

Item_cache *
Type_handler_timestamp_common::Item_get_cache(THD *thd, const Item *item) const
{
  return new (thd->mem_root) Item_cache_timestamp(thd);
}

Item_cache *
Type_handler_datetime_common::Item_get_cache(THD *thd, const Item *item) const
{
  return new (thd->mem_root) Item_cache_datetime(thd);
}

Item_cache *
Type_handler_time_common::Item_get_cache(THD *thd, const Item *item) const
{
  return new (thd->mem_root) Item_cache_time(thd);
}

Item_cache *
Type_handler_date_common::Item_get_cache(THD *thd, const Item *item) const
{
  return new (thd->mem_root) Item_cache_date(thd);
}


/*************************************************************************/

Item_copy *
Type_handler::create_item_copy(THD *thd, Item *item) const
{
  return new (thd->mem_root) Item_copy_string(thd, item);
}


Item_copy *
Type_handler_timestamp_common::create_item_copy(THD *thd, Item *item) const
{
  return new (thd->mem_root) Item_copy_timestamp(thd, item);
}

/*************************************************************************/

bool Type_handler_int_result::
       Item_hybrid_func_fix_attributes(THD *thd,
                                       const char *func_name,
                                       Type_handler_hybrid_field_type *handler,
                                       Type_all_attributes *func,
                                       Item **items, uint nitems) const
{
  bool unsigned_flag= items[0]->unsigned_flag;
  for (uint i= 1; i < nitems; i++)
  {
    if (unsigned_flag != items[i]->unsigned_flag)
    {
      // Convert a mixture of signed and unsigned int to decimal
      handler->set_handler(&type_handler_newdecimal);
      func->aggregate_attributes_decimal(items, nitems, false);
      return false;
    }
  }
  func->aggregate_attributes_int(items, nitems);
  handler->set_handler(func->unsigned_flag ?
                       handler->type_handler()->type_handler_unsigned() :
                       handler->type_handler()->type_handler_signed());
  return false;
}


bool Type_handler_real_result::
       Item_hybrid_func_fix_attributes(THD *thd,
                                       const char *func_name,
                                       Type_handler_hybrid_field_type *handler,
                                       Type_all_attributes *func,
                                       Item **items, uint nitems) const
{
  func->aggregate_attributes_real(items, nitems);
  return false;
}


bool Type_handler_decimal_result::
       Item_hybrid_func_fix_attributes(THD *thd,
                                       const char *func_name,
                                       Type_handler_hybrid_field_type *handler,
                                       Type_all_attributes *func,
                                       Item **items, uint nitems) const
{
  uint unsigned_count= func->count_unsigned(items, nitems);
  func->aggregate_attributes_decimal(items, nitems, unsigned_count == nitems);
  return false;
}


bool Type_handler_string_result::
       Item_hybrid_func_fix_attributes(THD *thd,
                                       const char *func_name,
                                       Type_handler_hybrid_field_type *handler,
                                       Type_all_attributes *func,
                                       Item **items, uint nitems) const
{
  return func->aggregate_attributes_string(func_name, items, nitems);
}



/*
  We can have enum/set type after merging only if we have one enum|set
  field (or MIN|MAX(enum|set field)) and number of NULL fields
*/
bool Type_handler_typelib::
       Item_hybrid_func_fix_attributes(THD *thd,
                                       const char *func_name,
                                       Type_handler_hybrid_field_type *handler,
                                       Type_all_attributes *func,
                                       Item **items, uint nitems) const
{
  const TYPELIB *typelib= NULL;
  for (uint i= 0; i < nitems; i++)
  {
    const TYPELIB *typelib2;
    if ((typelib2= items[i]->get_typelib()))
    {
      if (typelib)
      {
        /*
          Two ENUM/SET columns found. We convert such combinations to VARCHAR.
          This may change in the future to preserve ENUM/SET
          if typelib definitions are equal.
        */
        handler->set_handler(&type_handler_varchar);
        return func->aggregate_attributes_string(func_name, items, nitems);
      }
      typelib= typelib2;
    }
  }
  DBUG_ASSERT(typelib); // There must be at least one typelib
  func->set_typelib(typelib);
  return func->aggregate_attributes_string(func_name, items, nitems);
}


bool Type_handler_blob_common::
       Item_hybrid_func_fix_attributes(THD *thd,
                                       const char *func_name,
                                       Type_handler_hybrid_field_type *handler,
                                       Type_all_attributes *func,
                                       Item **items, uint nitems) const
{
  if (func->aggregate_attributes_string(func_name, items, nitems))
    return true;
  handler->set_handler(blob_type_handler(func->max_length));
  return false;
}


bool Type_handler_date_common::
       Item_hybrid_func_fix_attributes(THD *thd,
                                       const char *func_name,
                                       Type_handler_hybrid_field_type *handler,
                                       Type_all_attributes *func,
                                       Item **items, uint nitems) const
{
  func->fix_attributes_date();
  return false;
}


bool Type_handler_time_common::
       Item_hybrid_func_fix_attributes(THD *thd,
                                       const char *func_name,
                                       Type_handler_hybrid_field_type *handler,
                                       Type_all_attributes *func,
                                       Item **items, uint nitems) const
{
  func->aggregate_attributes_temporal(MIN_TIME_WIDTH, items, nitems);
  return false;
}


bool Type_handler_datetime_common::
       Item_hybrid_func_fix_attributes(THD *thd,
                                       const char *func_name,
                                       Type_handler_hybrid_field_type *handler,
                                       Type_all_attributes *func,
                                       Item **items, uint nitems) const
{
  func->aggregate_attributes_temporal(MAX_DATETIME_WIDTH, items, nitems);
  return false;
}


bool Type_handler_timestamp_common::
       Item_hybrid_func_fix_attributes(THD *thd,
                                       const char *func_name,
                                       Type_handler_hybrid_field_type *handler,
                                       Type_all_attributes *func,
                                       Item **items, uint nitems) const
{
  func->aggregate_attributes_temporal(MAX_DATETIME_WIDTH, items, nitems);
  return false;
}

/*************************************************************************/

bool Type_handler::
       Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
                                        Item **items, uint nitems) const
{
  /*
    Aggregating attributes for LEAST/GREATES is exactly the same
    with aggregating for CASE-alike functions (e.g. COALESCE)
    for the majority of data type handlers.
  */
  return Item_hybrid_func_fix_attributes(thd, func->func_name(),
                                         func, func, items, nitems);
}


bool Type_handler_temporal_result::
       Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
                                        Item **items, uint nitems) const
{
  DBUG_ASSERT(func->field_type() != MYSQL_TYPE_DATE);
  bool rc= Type_handler::Item_func_min_max_fix_attributes(thd, func,
                                                          items, nitems);
  bool is_time= func->field_type() == MYSQL_TYPE_TIME;
  func->decimals= 0;
  for (uint i= 0; i < nitems; i++)
  {
    uint deci= is_time ? items[i]->time_precision(thd) :
                         items[i]->datetime_precision(thd);
    set_if_bigger(func->decimals, deci);
  }

  if (rc || func->maybe_null)
    return rc;
  /*
    LEAST/GREATES(non-temporal, temporal) can return NULL.
    CAST functions Item_{time|datetime|date}_typecast always set maybe_full
    to true. Here we try to detect nullability more thoroughly.
    Perhaps CAST functions should also reuse this idea eventually.
  */
  const Type_handler *hf= func->type_handler();
  for (uint i= 0; i < nitems; i++)
  {
    /*
      If items[i] does not need conversion to the current temporal data
      type, then we trust items[i]->maybe_null, which was already ORred
      to func->maybe_null in the argument loop in fix_fields().
      If items[i] requires conversion to the current temporal data type,
      then conversion can fail and return NULL even for NOT NULL items.
    */
    const Type_handler *ha= items[i]->type_handler();
    if (hf == ha)
      continue; // No conversion.
    if (ha->cmp_type() != TIME_RESULT)
    {
      func->maybe_null= true; // Conversion from non-temporal is not safe
      break;
    }
    timestamp_type tf= hf->mysql_timestamp_type();
    timestamp_type ta= ha->mysql_timestamp_type();
    if (tf == ta ||
        (tf == MYSQL_TIMESTAMP_DATETIME && ta == MYSQL_TIMESTAMP_DATE))
    {
      /*
        If handlers have the same mysql_timestamp_type(),
        then conversion is NULL safe. Conversion from DATE to DATETIME
        is also safe. This branch includes data type pairs:
        Function return type Argument type  Comment
        -------------------- -------------  -------------
        TIMESTAMP            TIMESTAMP      no conversion
        TIMESTAMP            DATETIME       not possible
        TIMESTAMP            DATE           not possible
        DATETIME             DATETIME       no conversion
        DATETIME             TIMESTAMP      safe conversion
        DATETIME             DATE           safe conversion
        TIME                 TIME           no conversion

        Note, a function cannot return TIMESTAMP if it has non-TIMESTAMP
        arguments (it would return DATETIME in such case).
      */
      DBUG_ASSERT(hf->field_type() != MYSQL_TYPE_TIMESTAMP || tf == ta);
      continue;
    }
    /*
      Here we have the following data type pairs that did not match
      the condition above:

      Function return type Argument type Comment
      -------------------- ------------- -------
      TIMESTAMP            TIME          Not possible
      DATETIME             TIME          depends on OLD_MODE_ZERO_DATE_TIME_CAST
      TIME                 TIMESTAMP     Not possible
      TIME                 DATETIME      Not possible
      TIME                 DATE          Not possible

      Most pairs are not possible, because the function data type
      would be DATETIME (according to LEAST/GREATEST aggregation rules).
      Conversion to DATETIME from TIME is not safe when
      OLD_MODE_ZERO_DATE_TIME_CAST is set:
      - negative TIME values cannot be converted to not-NULL DATETIME values
      - TIME values can produce DATETIME values that do not pass
        NO_ZERO_DATE and NO_ZERO_IN_DATE tests.
    */
    DBUG_ASSERT(hf->field_type() == MYSQL_TYPE_DATETIME);
    if (!(thd->variables.old_behavior & OLD_MODE_ZERO_DATE_TIME_CAST))
      continue;
    func->maybe_null= true;
    break;
  }
  return rc;
}


bool Type_handler_date_common::
       Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
                                        Item **items, uint nitems) const
{
  func->fix_attributes_date();
  if (func->maybe_null)
    return false;
  /*
    We cannot trust the generic maybe_null value calculated during fix_fields().
    If a conversion from non-temoral types to DATE happens,
    then the result can be NULL (even if all arguments are not NULL).
  */
  for (uint i= 0; i < nitems; i++)
  {
    if (items[i]->type_handler()->cmp_type() != TIME_RESULT)
    {
      func->maybe_null= true;
      break;
    }
  }
  return false;
}


bool Type_handler_real_result::
       Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
                                        Item **items, uint nitems) const
{
  /*
    DOUBLE is an exception and aggregates attributes differently
    for LEAST/GREATEST vs CASE-alike functions. See the comment in
    Item_func_min_max::aggregate_attributes_real().
  */
  func->aggregate_attributes_real(items, nitems);
  return false;
}

/*************************************************************************/

bool Type_handler_int_result::
       Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
  /*
    "this" is equal func->args[0]->type_handler() here, e.g. for MIN()/MAX().
    func->unsigned_flag is not reliably set yet.
    It will be set by the call below (copied from args[0]).
  */
  const Type_handler *h= is_unsigned()
                           ? (Type_handler *)&type_handler_ulonglong
                           : (Type_handler *)&type_handler_slonglong;
  return func->fix_length_and_dec_numeric(h);
}


bool Type_handler_bool::
       Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
  return func->fix_length_and_dec_numeric(&type_handler_bool);
}


bool Type_handler_real_result::
       Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
  (void) func->fix_length_and_dec_numeric(&type_handler_double);
  func->max_length= func->float_length(func->decimals);
  return false;
}


bool Type_handler_decimal_result::
       Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
  return func->fix_length_and_dec_numeric(&type_handler_newdecimal);
}


bool Type_handler_string_result::
       Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
  return func->fix_length_and_dec_string();
}


bool Type_handler_temporal_result::
       Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
  return func->fix_length_and_dec_generic();
}


/*************************************************************************/

bool Type_handler_int_result::
       Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_decimal_result::
       Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_temporal_result::
       Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_real_result::
       Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler_string_result::
       Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
{
  item->fix_length_and_dec_double();
  return false;
}




/*************************************************************************/

bool Type_handler_int_result::
       Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_decimal_result::
       Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_temporal_result::
       Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_real_result::
       Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler_string_result::
       Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
{
  item->fix_length_and_dec_double();
  return false;
}




/*************************************************************************/

bool Type_handler_int_result::
       Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_decimal_result::
       Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_temporal_result::
       Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_real_result::
       Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler_string_result::
       Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


/*************************************************************************/

bool Type_handler_real_result::Item_val_bool(Item *item) const
{
  return item->val_real() != 0.0;
}

bool Type_handler_int_result::Item_val_bool(Item *item) const
{
  return item->val_int() != 0;
}

bool Type_handler_temporal_result::Item_val_bool(Item *item) const
{
  return item->val_real() != 0.0;
}

bool Type_handler_string_result::Item_val_bool(Item *item) const
{
  return item->val_real() != 0.0;
}


/*************************************************************************/


bool Type_handler::Item_get_date_with_warn(THD *thd, Item *item,
                                           MYSQL_TIME *ltime,
                                           date_mode_t fuzzydate) const
{
  const TABLE_SHARE *s= item->field_table_or_null();
  Temporal::Warn_push warn(thd, s ? s->db.str : nullptr,
                           s ? s->table_name.str : nullptr,
                           item->field_name_or_null(), ltime, fuzzydate);
  Item_get_date(thd, item, &warn, ltime, fuzzydate);
  return ltime->time_type < 0;
}


bool Type_handler::Item_func_hybrid_field_type_get_date_with_warn(THD *thd,
                                              Item_func_hybrid_field_type *item,
                                              MYSQL_TIME *ltime,
                                              date_mode_t mode) const
{
  const TABLE_SHARE *s= item->field_table_or_null();
  Temporal::Warn_push warn(thd, s ? s->db.str : nullptr,
                           s ? s->table_name.str : nullptr,
                           item->field_name_or_null(), ltime, mode);
  Item_func_hybrid_field_type_get_date(thd, item, &warn, ltime, mode);
  return ltime->time_type < 0;
}


/************************************************************************/
void Type_handler_decimal_result::Item_get_date(THD *thd, Item *item,
                                                Temporal::Warn *warn,
                                                MYSQL_TIME *ltime,
                                                date_mode_t fuzzydate) const
{
  new(ltime) Temporal_hybrid(thd, warn, VDec(item).ptr(), fuzzydate);
}


void Type_handler_int_result::Item_get_date(THD *thd, Item *item,
                                            Temporal::Warn *warn,
                                            MYSQL_TIME *to,
                                            date_mode_t mode) const
{
  new(to) Temporal_hybrid(thd, warn, item->to_longlong_hybrid_null(), mode);
}


void Type_handler_year::Item_get_date(THD *thd, Item *item,
                                      Temporal::Warn *warn,
                                      MYSQL_TIME *ltime,
                                      date_mode_t fuzzydate) const
{
  VYear year(item);
  DBUG_ASSERT(!year.truncated());
  Longlong_hybrid_null nr(Longlong_null(year.to_YYYYMMDD(), year.is_null()),
                          item->unsigned_flag);
  new(ltime) Temporal_hybrid(thd, warn, nr, fuzzydate);
}


void Type_handler_real_result::Item_get_date(THD *thd, Item *item,
                                             Temporal::Warn *warn,
                                             MYSQL_TIME *ltime,
                                             date_mode_t fuzzydate) const
{
  new(ltime) Temporal_hybrid(thd, warn, item->to_double_null(), fuzzydate);
}


void Type_handler_string_result::Item_get_date(THD *thd, Item *item,
                                               Temporal::Warn *warn,
                                               MYSQL_TIME *ltime,
                                               date_mode_t mode) const
{
  StringBuffer<40> tmp;
  new(ltime) Temporal_hybrid(thd, warn, item->val_str(&tmp), mode);
}


void Type_handler_temporal_result::Item_get_date(THD *thd, Item *item,
                                                 Temporal::Warn *warn,
                                                 MYSQL_TIME *ltime,
                                                 date_mode_t fuzzydate) const
{
  DBUG_ASSERT(0); // Temporal type items must implement native get_date()
  item->null_value= true;
  set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
}


/*************************************************************************/

longlong Type_handler_real_result::
           Item_val_int_signed_typecast(Item *item) const
{
  return item->val_int_signed_typecast_from_real();
}

longlong Type_handler_int_result::
           Item_val_int_signed_typecast(Item *item) const
{
  return item->val_int();
}

longlong Type_handler_decimal_result::
           Item_val_int_signed_typecast(Item *item) const
{
  return VDec(item).to_longlong(false);
}

longlong Type_handler_temporal_result::
           Item_val_int_signed_typecast(Item *item) const
{
  return item->val_int();
}

longlong Type_handler_string_result::
           Item_val_int_signed_typecast(Item *item) const
{
  return item->val_int_signed_typecast_from_str();
}

/*************************************************************************/

longlong Type_handler_real_result::
           Item_val_int_unsigned_typecast(Item *item) const
{
  return item->val_int_unsigned_typecast_from_real();
}

longlong Type_handler_int_result::
           Item_val_int_unsigned_typecast(Item *item) const
{
  return item->val_int_unsigned_typecast_from_int();
}

longlong Type_handler_temporal_result::
           Item_val_int_unsigned_typecast(Item *item) const
{
  return item->val_int_unsigned_typecast_from_int();
}

longlong Type_handler_time_common::
           Item_val_int_unsigned_typecast(Item *item) const
{
  /*
    TODO: this should eventually be fixed to do rounding
    when TIME_ROUND_FRACTIONAL is enabled, together with
    Field_{tiny|short|long|longlong}::store_time_dec().
    See MDEV-19502.
  */
  THD *thd= current_thd;
  Time tm(thd, item);
  DBUG_ASSERT(!tm.is_valid_time() == item->null_value);
  if (!tm.is_valid_time())
    return 0;
  longlong res= tm.to_longlong();
  if (res < 0)
  {
    push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
                        ER_DATA_OVERFLOW, ER_THD(thd, ER_DATA_OVERFLOW),
                        ErrConvTime(tm.get_mysql_time()).ptr(),
                        "UNSIGNED BIGINT");
    return 0;
  }
  return res;
}

longlong Type_handler_string_result::
           Item_val_int_unsigned_typecast(Item *item) const
{
  return item->val_int_unsigned_typecast_from_str();
}

/*************************************************************************/

String *
Type_handler_real_result::Item_func_hex_val_str_ascii(Item_func_hex *item,
                                                      String *str) const
{
  return item->val_str_ascii_from_val_real(str);
}


String *
Type_handler_decimal_result::Item_func_hex_val_str_ascii(Item_func_hex *item,
                                                         String *str) const
{
  return item->val_str_ascii_from_val_real(str);
}


String *
Type_handler_int_result::Item_func_hex_val_str_ascii(Item_func_hex *item,
                                                     String *str) const
{
  return item->val_str_ascii_from_val_int(str);
}


String *
Type_handler_temporal_result::Item_func_hex_val_str_ascii(Item_func_hex *item,
                                                          String *str) const
{
  return item->val_str_ascii_from_val_str(str);
}


String *
Type_handler_string_result::Item_func_hex_val_str_ascii(Item_func_hex *item,
                                                        String *str) const
{
  return item->val_str_ascii_from_val_str(str);
}

/***************************************************************************/

String *
Type_handler_decimal_result::Item_func_hybrid_field_type_val_str(
                                              Item_func_hybrid_field_type *item,
                                              String *str) const
{
  return VDec_op(item).to_string_round(str, item->decimals);
}


double
Type_handler_decimal_result::Item_func_hybrid_field_type_val_real(
                                              Item_func_hybrid_field_type *item)
                                              const
{
  return VDec_op(item).to_double();
}


longlong
Type_handler_decimal_result::Item_func_hybrid_field_type_val_int(
                                              Item_func_hybrid_field_type *item)
                                              const
{
  return VDec_op(item).to_longlong(item->unsigned_flag);
}


my_decimal *
Type_handler_decimal_result::Item_func_hybrid_field_type_val_decimal(
                                              Item_func_hybrid_field_type *item,
                                              my_decimal *dec) const
{
  return VDec_op(item).to_decimal(dec);
}


void
Type_handler_decimal_result::Item_func_hybrid_field_type_get_date(
                                             THD *thd,
                                             Item_func_hybrid_field_type *item,
                                             Temporal::Warn *warn,
                                             MYSQL_TIME *ltime,
                                             date_mode_t fuzzydate) const
{
  new (ltime) Temporal_hybrid(thd, warn, VDec_op(item).ptr(), fuzzydate);
}


void
Type_handler_year::Item_func_hybrid_field_type_get_date(
                                             THD *thd,
                                             Item_func_hybrid_field_type *item,
                                             Temporal::Warn *warn,
                                             MYSQL_TIME *ltime,
                                             date_mode_t fuzzydate) const
{
  VYear_op year(item);
  DBUG_ASSERT(!year.truncated());
  Longlong_hybrid_null nr(Longlong_null(year.to_YYYYMMDD(), year.is_null()),
                          item->unsigned_flag);
  new(ltime) Temporal_hybrid(thd, warn, nr, fuzzydate);
}


/***************************************************************************/


String *
Type_handler_int_result::Item_func_hybrid_field_type_val_str(
                                          Item_func_hybrid_field_type *item,
                                          String *str) const
{
  return item->val_str_from_int_op(str);
}


double
Type_handler_int_result::Item_func_hybrid_field_type_val_real(
                                          Item_func_hybrid_field_type *item)
                                          const
{
  return item->val_real_from_int_op();
}


longlong
Type_handler_int_result::Item_func_hybrid_field_type_val_int(
                                          Item_func_hybrid_field_type *item)
                                          const
{
  return item->val_int_from_int_op();
}


my_decimal *
Type_handler_int_result::Item_func_hybrid_field_type_val_decimal(
                                          Item_func_hybrid_field_type *item,
                                          my_decimal *dec) const
{
  return item->val_decimal_from_int_op(dec);
}


void
Type_handler_int_result::Item_func_hybrid_field_type_get_date(
                                          THD *thd,
                                          Item_func_hybrid_field_type *item,
                                          Temporal::Warn *warn,
                                          MYSQL_TIME *to,
                                          date_mode_t mode) const
{
  new(to) Temporal_hybrid(thd, warn, item->to_longlong_hybrid_null_op(), mode);
}


/***************************************************************************/

String *
Type_handler_double::Item_func_hybrid_field_type_val_str(
                                           Item_func_hybrid_field_type *item,
                                           String *str) const
{
  return item->val_str_from_real_op(str);
}

String *
Type_handler_float::Item_func_hybrid_field_type_val_str(
                                           Item_func_hybrid_field_type *item,
                                           String *str) const
{
  Float nr(item->real_op());
  if (item->null_value)
    return 0;
  nr.to_string(str, item->decimals);
  return str;
}

double
Type_handler_real_result::Item_func_hybrid_field_type_val_real(
                                           Item_func_hybrid_field_type *item)
                                           const
{
  return item->val_real_from_real_op();
}


longlong
Type_handler_real_result::Item_func_hybrid_field_type_val_int(
                                           Item_func_hybrid_field_type *item)
                                           const
{
  return item->val_int_from_real_op();
}


my_decimal *
Type_handler_real_result::Item_func_hybrid_field_type_val_decimal(
                                           Item_func_hybrid_field_type *item,
                                           my_decimal *dec) const
{
  return item->val_decimal_from_real_op(dec);
}


void
Type_handler_real_result::Item_func_hybrid_field_type_get_date(
                                             THD *thd,
                                             Item_func_hybrid_field_type *item,
                                             Temporal::Warn *warn,
                                             MYSQL_TIME *to,
                                             date_mode_t mode) const
{
  new(to) Temporal_hybrid(thd, warn, item->to_double_null_op(), mode);
}


/***************************************************************************/

String *
Type_handler_temporal_result::Item_func_hybrid_field_type_val_str(
                                        Item_func_hybrid_field_type *item,
                                        String *str) const
{
  return item->val_str_from_date_op(str);
}


double
Type_handler_temporal_result::Item_func_hybrid_field_type_val_real(
                                        Item_func_hybrid_field_type *item)
                                        const
{
  return item->val_real_from_date_op();
}


longlong
Type_handler_temporal_result::Item_func_hybrid_field_type_val_int(
                                        Item_func_hybrid_field_type *item)
                                        const
{
  return item->val_int_from_date_op();
}


my_decimal *
Type_handler_temporal_result::Item_func_hybrid_field_type_val_decimal(
                                        Item_func_hybrid_field_type *item,
                                        my_decimal *dec) const
{
  return item->val_decimal_from_date_op(dec);
}


void
Type_handler_temporal_result::Item_func_hybrid_field_type_get_date(
                                        THD *thd,
                                        Item_func_hybrid_field_type *item,
                                        Temporal::Warn *warn,
                                        MYSQL_TIME *ltime,
                                        date_mode_t fuzzydate) const
{
  if (item->date_op(thd, ltime, fuzzydate))
    set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
}


/***************************************************************************/

String *
Type_handler_time_common::Item_func_hybrid_field_type_val_str(
                                    Item_func_hybrid_field_type *item,
                                    String *str) const
{
  return item->val_str_from_time_op(str);
}


double
Type_handler_time_common::Item_func_hybrid_field_type_val_real(
                                    Item_func_hybrid_field_type *item)
                                    const
{
  return item->val_real_from_time_op();
}


longlong
Type_handler_time_common::Item_func_hybrid_field_type_val_int(
                                    Item_func_hybrid_field_type *item)
                                    const
{
  return item->val_int_from_time_op();
}


my_decimal *
Type_handler_time_common::Item_func_hybrid_field_type_val_decimal(
                                    Item_func_hybrid_field_type *item,
                                    my_decimal *dec) const
{
  return item->val_decimal_from_time_op(dec);
}


void
Type_handler_time_common::Item_func_hybrid_field_type_get_date(
                                    THD *thd,
                                    Item_func_hybrid_field_type *item,
                                    Temporal::Warn *warn,
                                    MYSQL_TIME *ltime,
                                    date_mode_t fuzzydate) const
{
  if (item->time_op(thd, ltime))
    set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
}


/***************************************************************************/

String *
Type_handler_string_result::Item_func_hybrid_field_type_val_str(
                                             Item_func_hybrid_field_type *item,
                                             String *str) const
{
  return item->val_str_from_str_op(str);
}


double
Type_handler_string_result::Item_func_hybrid_field_type_val_real(
                                             Item_func_hybrid_field_type *item)
                                             const
{
  return item->val_real_from_str_op();
}


longlong
Type_handler_string_result::Item_func_hybrid_field_type_val_int(
                                             Item_func_hybrid_field_type *item)
                                             const
{
  return item->val_int_from_str_op();
}


my_decimal *
Type_handler_string_result::Item_func_hybrid_field_type_val_decimal(
                                              Item_func_hybrid_field_type *item,
                                              my_decimal *dec) const
{
  return item->val_decimal_from_str_op(dec);
}


void
Type_handler_string_result::Item_func_hybrid_field_type_get_date(
                                             THD *thd,
                                             Item_func_hybrid_field_type *item,
                                             Temporal::Warn *warn,
                                             MYSQL_TIME *ltime,
                                             date_mode_t mode) const
{
  StringBuffer<40> tmp;
  String *res= item->str_op(&tmp);
  DBUG_ASSERT((res == NULL) == item->null_value);
  new(ltime) Temporal_hybrid(thd, warn, res, mode);
}

/***************************************************************************/

bool Type_handler_numeric::
       Item_func_between_fix_length_and_dec(Item_func_between *func) const
{
  return func->fix_length_and_dec_numeric(current_thd);
}

bool Type_handler_temporal_result::
       Item_func_between_fix_length_and_dec(Item_func_between *func) const
{
  return func->fix_length_and_dec_temporal(current_thd);
}

bool Type_handler_string_result::
       Item_func_between_fix_length_and_dec(Item_func_between *func) const
{
  return func->fix_length_and_dec_string(current_thd);
}


longlong Type_handler_row::
           Item_func_between_val_int(Item_func_between *func) const
{
  DBUG_ASSERT(0);
  func->null_value= true;
  return 0;
}

longlong Type_handler_string_result::
           Item_func_between_val_int(Item_func_between *func) const
{
  return func->val_int_cmp_string();
}

longlong Type_handler_temporal_with_date::
           Item_func_between_val_int(Item_func_between *func) const
{
  return func->val_int_cmp_datetime();
}

longlong Type_handler_time_common::
           Item_func_between_val_int(Item_func_between *func) const
{
  return func->val_int_cmp_time();
}

longlong Type_handler_timestamp_common::
           Item_func_between_val_int(Item_func_between *func) const
{
  return func->val_int_cmp_native();
}

longlong Type_handler_int_result::
           Item_func_between_val_int(Item_func_between *func) const
{
  return func->val_int_cmp_int();
}

longlong Type_handler_real_result::
           Item_func_between_val_int(Item_func_between *func) const
{
  return func->val_int_cmp_real();
}

longlong Type_handler_decimal_result::
           Item_func_between_val_int(Item_func_between *func) const
{
  return func->val_int_cmp_decimal();
}

/***************************************************************************/

cmp_item *Type_handler_int_result::make_cmp_item(THD *thd,
                                                 CHARSET_INFO *cs) const
{
  return new (thd->mem_root) cmp_item_int;
}

cmp_item *Type_handler_real_result::make_cmp_item(THD *thd,
                                                 CHARSET_INFO *cs) const
{
  return new (thd->mem_root) cmp_item_real;
}

cmp_item *Type_handler_decimal_result::make_cmp_item(THD *thd,
                                                     CHARSET_INFO *cs) const
{
  return new (thd->mem_root) cmp_item_decimal;
}


cmp_item *Type_handler_string_result::make_cmp_item(THD *thd,
                                                    CHARSET_INFO *cs) const
{
  return new (thd->mem_root) cmp_item_sort_string(cs);
}

cmp_item *Type_handler_row::make_cmp_item(THD *thd,
                                                    CHARSET_INFO *cs) const
{
  return new (thd->mem_root) cmp_item_row;
}

cmp_item *Type_handler_time_common::make_cmp_item(THD *thd,
                                                    CHARSET_INFO *cs) const
{
  return new (thd->mem_root) cmp_item_time;
}

cmp_item *Type_handler_temporal_with_date::make_cmp_item(THD *thd,
                                                    CHARSET_INFO *cs) const
{
  return new (thd->mem_root) cmp_item_datetime;
}

cmp_item *Type_handler_timestamp_common::make_cmp_item(THD *thd,
                                                       CHARSET_INFO *cs) const
{
  return new (thd->mem_root) cmp_item_timestamp;
}

/***************************************************************************/

static int srtcmp_in(const void *cs_, const void *x_, const void *y_)
{
  const CHARSET_INFO *cs= static_cast<const CHARSET_INFO *>(cs_);
  const String *x= static_cast<const String *>(x_);
  const String *y= static_cast<const String *>(y_);
  return cs->strnncollsp(x->ptr(), x->length(), y->ptr(), y->length());
}

in_vector *Type_handler_string_result::make_in_vector(THD *thd,
                                                      const Item_func_in *func,
                                                      uint nargs) const
{
  return new (thd->mem_root) in_string(thd, nargs, (qsort2_cmp) srtcmp_in,
                                       func->compare_collation());

}


in_vector *Type_handler_int_result::make_in_vector(THD *thd,
                                                   const Item_func_in *func,
                                                   uint nargs) const
{
  return new (thd->mem_root) in_longlong(thd, nargs);
}


in_vector *Type_handler_real_result::make_in_vector(THD *thd,
                                                    const Item_func_in *func,
                                                    uint nargs) const
{
  return new (thd->mem_root) in_double(thd, nargs);
}


in_vector *Type_handler_decimal_result::make_in_vector(THD *thd,
                                                       const Item_func_in *func,
                                                       uint nargs) const
{
  return new (thd->mem_root) in_decimal(thd, nargs);
}


in_vector *Type_handler_time_common::make_in_vector(THD *thd,
                                                    const Item_func_in *func,
                                                    uint nargs) const
{
  return new (thd->mem_root) in_time(thd, nargs);
}


in_vector *
Type_handler_temporal_with_date::make_in_vector(THD *thd,
                                                const Item_func_in *func,
                                                uint nargs) const
{
  return new (thd->mem_root) in_datetime(thd, nargs);
}


in_vector *
Type_handler_timestamp_common::make_in_vector(THD *thd,
                                              const Item_func_in *func,
                                              uint nargs) const
{
  return new (thd->mem_root) in_timestamp(thd, nargs);
}


in_vector *Type_handler_row::make_in_vector(THD *thd,
                                            const Item_func_in *func,
                                            uint nargs) const
{
  return new (thd->mem_root) in_row(thd, nargs, 0);
}

/***************************************************************************/

bool Type_handler_string_result::
       Item_func_in_fix_comparator_compatible_types(THD *thd,
                                                    Item_func_in *func) const
{
  if (func->agg_all_arg_charsets_for_comparison())
    return true;
  if (func->compatible_types_scalar_bisection_possible())
  {
    return func->value_list_convert_const_to_int(thd) ||
           func->fix_for_scalar_comparison_using_bisection(thd);
  }
  return
    func->fix_for_scalar_comparison_using_cmp_items(thd,
                                                    1U << (uint) STRING_RESULT);
}


bool Type_handler_int_result::
       Item_func_in_fix_comparator_compatible_types(THD *thd,
                                                    Item_func_in *func) const
{
  /*
     Does not need to call value_list_convert_const_to_int()
     as already handled by int handler.
  */
  return func->compatible_types_scalar_bisection_possible() ?
    func->fix_for_scalar_comparison_using_bisection(thd) :
    func->fix_for_scalar_comparison_using_cmp_items(thd,
                                                    1U << (uint) INT_RESULT);
}


bool Type_handler_real_result::
       Item_func_in_fix_comparator_compatible_types(THD *thd,
                                                    Item_func_in *func) const
{
  return func->compatible_types_scalar_bisection_possible() ?
    (func->value_list_convert_const_to_int(thd) ||
     func->fix_for_scalar_comparison_using_bisection(thd)) :
    func->fix_for_scalar_comparison_using_cmp_items(thd,
                                                    1U << (uint) REAL_RESULT);
}


bool Type_handler_decimal_result::
       Item_func_in_fix_comparator_compatible_types(THD *thd,
                                                    Item_func_in *func) const
{
  return func->compatible_types_scalar_bisection_possible() ?
    (func->value_list_convert_const_to_int(thd) ||
     func->fix_for_scalar_comparison_using_bisection(thd)) :
    func->fix_for_scalar_comparison_using_cmp_items(thd,
                                                    1U << (uint) DECIMAL_RESULT);
}


bool Type_handler_temporal_result::
       Item_func_in_fix_comparator_compatible_types(THD *thd,
                                                    Item_func_in *func) const
{
  return func->compatible_types_scalar_bisection_possible() ?
    (func->value_list_convert_const_to_int(thd) ||
     func->fix_for_scalar_comparison_using_bisection(thd)) :
    func->fix_for_scalar_comparison_using_cmp_items(thd,
                                                    1U << (uint) TIME_RESULT);
}


bool Type_handler_row::Item_func_in_fix_comparator_compatible_types(THD *thd,
                                              Item_func_in *func) const
{
  return func->compatible_types_row_bisection_possible() ?
         func->fix_for_row_comparison_using_bisection(thd) :
         func->fix_for_row_comparison_using_cmp_items(thd);
}

/***************************************************************************/

String *Type_handler_string_result::
          Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
{
  return func->val_str_native(str);
}


String *Type_handler_time_common::
          Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
{
  return Time(func).to_string(str, func->decimals);
}


String *Type_handler_date_common::
          Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
{
  return Date(func).to_string(str);
}


String *Type_handler_datetime_common::
          Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
{
  return Datetime(func).to_string(str, func->decimals);
}


String *Type_handler_timestamp_common::
          Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
{
  THD *thd= current_thd;
  return Timestamp_or_zero_datetime_native_null(thd, func).
           to_datetime(thd).to_string(str, func->decimals);
}


String *Type_handler_int_result::
          Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
{
  return func->val_string_from_int(str);
}


String *Type_handler_decimal_result::
          Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
{
  return VDec(func).to_string_round(str, func->decimals);
}


String *Type_handler_double::
          Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
{
  return func->val_string_from_real(str);
}


String *Type_handler_float::
          Item_func_min_max_val_str(Item_func_min_max *func, String *str) const
{
  Float nr(func->val_real());
  if (func->null_value)
    return 0;
  nr.to_string(str, func->decimals);
  return str;
}


double Type_handler_string_result::
         Item_func_min_max_val_real(Item_func_min_max *func) const
{
  return func->val_real_native();
}


double Type_handler_time_common::
         Item_func_min_max_val_real(Item_func_min_max *func) const
{
  return Time(current_thd, func).to_double();
}


double Type_handler_date_common::
         Item_func_min_max_val_real(Item_func_min_max *func) const
{
  return Date(current_thd, func).to_double();
}


double Type_handler_datetime_common::
         Item_func_min_max_val_real(Item_func_min_max *func) const
{
  return Datetime(current_thd, func).to_double();
}


double Type_handler_timestamp_common::
         Item_func_min_max_val_real(Item_func_min_max *func) const
{
  THD *thd= current_thd;
  return Timestamp_or_zero_datetime_native_null(thd, func).
           to_datetime(thd).to_double();
}


double Type_handler_numeric::
         Item_func_min_max_val_real(Item_func_min_max *func) const
{
  return func->val_real_native();
}


longlong Type_handler_string_result::
         Item_func_min_max_val_int(Item_func_min_max *func) const
{
  return func->val_int_native();
}


longlong Type_handler_time_common::
         Item_func_min_max_val_int(Item_func_min_max *func) const
{
  return Time(current_thd, func).to_longlong();
}


longlong Type_handler_date_common::
         Item_func_min_max_val_int(Item_func_min_max *func) const
{
  return Date(current_thd, func).to_longlong();
}


longlong Type_handler_datetime_common::
         Item_func_min_max_val_int(Item_func_min_max *func) const
{
  return Datetime(current_thd, func).to_longlong();
}


longlong Type_handler_timestamp_common::
         Item_func_min_max_val_int(Item_func_min_max *func) const
{
  THD *thd= current_thd;
  return Timestamp_or_zero_datetime_native_null(thd, func).
           to_datetime(thd).to_longlong();
}


longlong Type_handler_numeric::
         Item_func_min_max_val_int(Item_func_min_max *func) const
{
  return func->val_int_native();
}


my_decimal *Type_handler_string_result::
            Item_func_min_max_val_decimal(Item_func_min_max *func,
                                          my_decimal *dec) const
{
  return func->val_decimal_native(dec);
}


my_decimal *Type_handler_numeric::
            Item_func_min_max_val_decimal(Item_func_min_max *func,
                                          my_decimal *dec) const
{
  return func->val_decimal_native(dec);
}


my_decimal *Type_handler_time_common::
            Item_func_min_max_val_decimal(Item_func_min_max *func,
                                          my_decimal *dec) const
{
  return Time(current_thd, func).to_decimal(dec);
}


my_decimal *Type_handler_date_common::
            Item_func_min_max_val_decimal(Item_func_min_max *func,
                                          my_decimal *dec) const
{
  return Date(current_thd, func).to_decimal(dec);
}


my_decimal *Type_handler_datetime_common::
            Item_func_min_max_val_decimal(Item_func_min_max *func,
                                          my_decimal *dec) const
{
  return Datetime(current_thd, func).to_decimal(dec);
}


my_decimal *Type_handler_timestamp_common::
            Item_func_min_max_val_decimal(Item_func_min_max *func,
                                          my_decimal *dec) const
{
  THD *thd= current_thd;
  return Timestamp_or_zero_datetime_native_null(thd, func).
           to_datetime(thd).to_decimal(dec);
}


bool Type_handler_string_result::
       Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
                                  MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
  /*
    just like ::val_int() method of a string item can be called,
    for example, SELECT CONCAT("10", "12") + 1,
    ::get_date() can be called for non-temporal values,
    for example, SELECT MONTH(GREATEST("2011-11-21", "2010-10-09"))
  */
  return func->get_date_from_string(thd, ltime, fuzzydate);
}


bool Type_handler_numeric::
       Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
                                  MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
  return Item_get_date_with_warn(thd, func, ltime, fuzzydate);
}


bool Type_handler_temporal_result::
       Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
                                  MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
  /*
    - If the caller specified TIME_TIME_ONLY, then it's going to convert
      a DATETIME or DATE to TIME. So we pass the default flags for date. This is
      exactly the same with what Item_func_min_max_val_{int|real|decimal|str} or
      Item_send_datetime() do. We return the value in accordance with the
      current session date flags and let the caller further convert it to TIME.
    - If the caller did not specify TIME_TIME_ONLY, then return the value
      according to the flags supplied by the caller.
  */
  return func->get_date_native(thd, ltime,
                               fuzzydate & TIME_TIME_ONLY ?
                               Datetime::Options(thd) :
                               fuzzydate);
}

bool Type_handler_time_common::
       Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
                                  MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
  return func->get_time_native(thd, ltime);
}


bool Type_handler_timestamp_common::
       Item_func_min_max_get_date(THD *thd, Item_func_min_max *func,
                                  MYSQL_TIME *ltime, date_mode_t fuzzydate) const
{
  return Timestamp_or_zero_datetime_native_null(thd, func).
           to_datetime(thd).copy_to_mysql_time(ltime);
}

/***************************************************************************/

/**
  Get a string representation of the Item value.
  See sql_type.h for details.
*/
String *Type_handler_row::
          print_item_value(THD *thd, Item *item, String *str) const
{
  CHARSET_INFO *cs= thd->variables.character_set_client;
  StringBuffer<STRING_BUFFER_USUAL_SIZE> val(cs);
  str->append(STRING_WITH_LEN("ROW("));
  for (uint i= 0 ; i < item->cols(); i++)
  {
    if (i > 0)
      str->append(',');
    Item *elem= item->element_index(i);
    String *tmp= elem->type_handler()->print_item_value(thd, elem, &val);
    if (tmp)
      str->append(*tmp);
    else
      str->append(STRING_WITH_LEN("NULL"));
  }
  str->append(STRING_WITH_LEN(")"));
  return str;
}


/**
  Get a string representation of the Item value,
  using the character string format with its charset and collation, e.g.
    latin1 'string' COLLATE latin1_german2_ci
*/
String *Type_handler::
          print_item_value_csstr(THD *thd, Item *item, String *str) const
{
  String *result= item->val_str(str);

  if (!result)
    return NULL;

  StringBuffer<STRING_BUFFER_USUAL_SIZE> buf(result->charset());
  CHARSET_INFO *cs= thd->variables.character_set_client;

  buf.append('_');
  buf.append(result->charset()->csname);
  if (cs->escape_with_backslash_is_dangerous)
    buf.append(' ');
  append_query_string(cs, &buf, result->ptr(), result->length(),
                     thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES);
  buf.append(" COLLATE '");
  buf.append(item->collation.collation->name);
  buf.append('\'');
  str->copy(buf);

  return str;
}


String *Type_handler_numeric::
          print_item_value(THD *thd, Item *item, String *str) const
{
  return item->val_str(str);
}


String *Type_handler::
          print_item_value_temporal(THD *thd, Item *item, String *str,
                                    const Name &type_name, String *buf) const
{
  String *result= item->val_str(buf);
  return !result ||
         str->realloc(type_name.length() + result->length() + 2) ||
         str->copy(type_name.ptr(), type_name.length(), &my_charset_latin1) ||
         str->append('\'') ||
         str->append(result->ptr(), result->length()) ||
         str->append('\'') ?
         NULL :
         str;
}


String *Type_handler_time_common::
          print_item_value(THD *thd, Item *item, String *str) const
{
  StringBuffer<MAX_TIME_FULL_WIDTH+1> buf;
  return print_item_value_temporal(thd, item, str,
                                   Name(STRING_WITH_LEN("TIME")), &buf);
}


String *Type_handler_date_common::
          print_item_value(THD *thd, Item *item, String *str) const
{
  StringBuffer<MAX_DATE_WIDTH+1> buf;
  return print_item_value_temporal(thd, item, str,
                                   Name(STRING_WITH_LEN("DATE")), &buf);
}


String *Type_handler_datetime_common::
          print_item_value(THD *thd, Item *item, String *str) const
{
  StringBuffer<MAX_DATETIME_FULL_WIDTH+1> buf;
  return print_item_value_temporal(thd, item, str,
                                   Name(STRING_WITH_LEN("TIMESTAMP")), &buf);
}


String *Type_handler_timestamp_common::
          print_item_value(THD *thd, Item *item, String *str) const
{
  StringBuffer<MAX_DATETIME_FULL_WIDTH+1> buf;
  return print_item_value_temporal(thd, item, str,
                                   Name(STRING_WITH_LEN("TIMESTAMP")), &buf);
}


/***************************************************************************/

bool Type_handler_row::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  DBUG_ASSERT(0);
  return false;
}


bool Type_handler_int_result::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  item->fix_arg_int(this, item->arguments()[0],
                    field_type() == MYSQL_TYPE_LONGLONG);
  return false;
}


bool Type_handler_year::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  item->fix_arg_int(&type_handler_ulong, item->arguments()[0], false);
  return false;
}


bool Type_handler_hex_hybrid::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  item->fix_arg_hex_hybrid();
  return false;
}


bool Type_handler_bit::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  uint nbits= item->arguments()[0]->max_length;
  item->fix_length_and_dec_ulong_or_ulonglong_by_nbits(nbits);
  return false;
}


bool Type_handler_typelib::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  item->fix_length_and_dec_long_or_longlong(5, true);
  return false;
}


bool Type_handler_real_result::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  item->fix_arg_double();
  return false;
}


bool Type_handler_decimal_result::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  item->fix_arg_decimal();
  return false;
}


bool Type_handler_date_common::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  static const Type_std_attributes attr(Type_numeric_attributes(8, 0, true),
                                        DTCollation_numeric());
  item->fix_arg_int(&type_handler_ulong, &attr, false);
  return false;
}


bool Type_handler_time_common::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  item->fix_arg_time();
  return false;
}


bool Type_handler_datetime_common::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  item->fix_arg_datetime();
  return false;
}


bool Type_handler_timestamp_common::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  item->fix_arg_datetime();
  return false;
}


bool Type_handler_string_result::
       Item_func_round_fix_length_and_dec(Item_func_round *item) const
{
  item->fix_arg_double();
  return false;
}


/***************************************************************************/

bool Type_handler_row::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  DBUG_ASSERT(0);
  return false;
}


bool Type_handler_int_result::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  item->Type_std_attributes::set(item->arguments()[0]);
  item->set_handler(this);
  return false;
}


bool Type_handler_year::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  item->Type_std_attributes::set(item->arguments()[0]);
  item->set_handler(&type_handler_ulong);
  return false;
}


bool Type_handler_bit::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  uint nbits= item->arguments()[0]->max_length;
  item->fix_length_and_dec_ulong_or_ulonglong_by_nbits(nbits);
  return false;
}


bool Type_handler_typelib::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  item->fix_length_and_dec_long_or_longlong(5, true);
  return false;
}


bool Type_handler_hex_hybrid::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  uint nchars= item->arguments()[0]->decimal_precision();
  item->fix_length_and_dec_long_or_longlong(nchars, true);
  return false;
}


bool Type_handler_real_result::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler_decimal_result::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  item->fix_length_and_dec_int_or_decimal();
  return false;
}


bool Type_handler_date_common::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  static const Type_numeric_attributes attr(8, 0/*dec*/, true/*unsigned*/);
  item->Type_std_attributes::set(attr, DTCollation_numeric());
  item->set_handler(&type_handler_ulong);
  return false;
}


bool Type_handler_time_common::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  item->fix_length_and_dec_time();
  return false;
}


bool Type_handler_datetime_common::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  item->fix_length_and_dec_datetime();
  return false;
}


bool Type_handler_timestamp_common::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  item->fix_length_and_dec_datetime();
  return false;
}


bool Type_handler_string_result::
       Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


/***************************************************************************/

bool Type_handler_row::
       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
{
  DBUG_ASSERT(0);
  return false;
}


bool Type_handler_int_result::
       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
{
  item->fix_length_and_dec_int();
  return false;
}


bool Type_handler_real_result::
       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler_decimal_result::
       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_temporal_result::
       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_string_result::
       Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


/***************************************************************************/

bool Type_handler_row::
       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
{
  DBUG_ASSERT(0);
  return false;
}


bool Type_handler_int_result::
       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
{
  item->fix_length_and_dec_int();
  return false;
}


bool Type_handler_real_result::
       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler_decimal_result::
       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_temporal_result::
       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_string_result::
       Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


/***************************************************************************/

bool Type_handler::
       Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
{
  item->fix_length_and_dec_generic();
  return false;
}


bool Type_handler::
       Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
{
  const Item *arg= item->arguments()[0];
  if (!arg->unsigned_flag && arg->val_int_min() < 0)
  {
    /*
      Negative arguments produce long results:
        CAST(1-2 AS UNSIGNED) -> 18446744073709551615
    */
    item->max_length= MAX_BIGINT_WIDTH;
    return false;
  }
  item->fix_length_and_dec_generic();
  return false;
}


bool Type_handler_string_result::
       Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
{
  item->fix_length_and_dec_string();
  return false;
}


bool Type_handler_string_result::
       Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
{
  const Item *arg= item->arguments()[0];
  if (!arg->unsigned_flag &&       // Not HEX hybrid
      arg->max_char_length() > 1)  // Can be negative
  {
    // String arguments can give long results: '-1' -> 18446744073709551614
    item->max_length= MAX_BIGINT_WIDTH;
    return false;
  }
  item->fix_length_and_dec_string();
  return false;
}

bool Type_handler_real_result::
       Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler_real_result::
       Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler::
       Item_double_typecast_fix_length_and_dec(Item_double_typecast *item) const
{
  item->fix_length_and_dec_generic();
  return false;
}


bool Type_handler::
       Item_float_typecast_fix_length_and_dec(Item_float_typecast *item) const
{
  item->fix_length_and_dec_generic();
  return false;
}


bool Type_handler::
       Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *item) const
{
  item->fix_length_and_dec_generic();
  return false;
}


bool Type_handler::
       Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
{
  item->fix_length_and_dec_generic();
  return false;
}


bool Type_handler_numeric::
       Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
{
  item->fix_length_and_dec_numeric();
  return false;
}


bool Type_handler_string_result::
       Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
{
  item->fix_length_and_dec_str();
  return false;
}


bool Type_handler::
       Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const
{
  uint dec= item->decimals == NOT_FIXED_DEC ?
            item->arguments()[0]->time_precision(current_thd) :
            item->decimals;
  item->fix_attributes_temporal(MIN_TIME_WIDTH, dec);
  item->maybe_null= true;
  return false;
}


bool Type_handler::
       Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const
{
  item->fix_attributes_temporal(MAX_DATE_WIDTH, 0);
  item->maybe_null= true;
  return false;
}


bool Type_handler::
       Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item)
                                                 const
{
  uint dec= item->decimals == NOT_FIXED_DEC ?
            item->arguments()[0]->datetime_precision(current_thd) :
            item->decimals;
  item->fix_attributes_temporal(MAX_DATETIME_WIDTH, dec);
  item->maybe_null= true;
  return false;
}


/***************************************************************************/

bool Type_handler_row::
       Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
{
  DBUG_ASSERT(0);
  return true;
}


bool Type_handler_int_result::
       Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
{
  item->fix_length_and_dec_int();
  return false;
}


bool Type_handler_real_result::
       Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler_decimal_result::
       Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_temporal_result::
       Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
{
  item->fix_length_and_dec_temporal(true);
  return false;
}


bool Type_handler_string_result::
       Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
{
  item->fix_length_and_dec_double();
  return false;
}

/***************************************************************************/

bool Type_handler_row::
       Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
{
  DBUG_ASSERT(0);
  return true;
}


bool Type_handler_int_result::
       Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
{
  item->fix_length_and_dec_int();
  return false;
}


bool Type_handler_real_result::
       Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler_decimal_result::
       Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_temporal_result::
       Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
{
  item->fix_length_and_dec_temporal(true);
  return false;
}


bool Type_handler_string_result::
       Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
{
  item->fix_length_and_dec_double();
  return false;
}

/***************************************************************************/

bool Type_handler_row::
       Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
{
  DBUG_ASSERT(0);
  return true;
}


bool Type_handler_int_result::
       Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
{
  item->fix_length_and_dec_int();
  return false;
}


bool Type_handler_real_result::
       Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler_decimal_result::
       Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_temporal_result::
       Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
{
  item->fix_length_and_dec_temporal(true);
  return false;
}


bool Type_handler_string_result::
       Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
{
  item->fix_length_and_dec_double();
  return false;
}

/***************************************************************************/

bool Type_handler_row::
       Item_func_div_fix_length_and_dec(Item_func_div *item) const
{
  DBUG_ASSERT(0);
  return true;
}


bool Type_handler_int_result::
       Item_func_div_fix_length_and_dec(Item_func_div *item) const
{
  item->fix_length_and_dec_int();
  return false;
}


bool Type_handler_real_result::
       Item_func_div_fix_length_and_dec(Item_func_div *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler_decimal_result::
       Item_func_div_fix_length_and_dec(Item_func_div *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_temporal_result::
       Item_func_div_fix_length_and_dec(Item_func_div *item) const
{
  item->fix_length_and_dec_temporal(false);
  return false;
}


bool Type_handler_string_result::
       Item_func_div_fix_length_and_dec(Item_func_div *item) const
{
  item->fix_length_and_dec_double();
  return false;
}

/***************************************************************************/

bool Type_handler_row::
       Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
{
  DBUG_ASSERT(0);
  return true;
}


bool Type_handler_int_result::
       Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
{
  item->fix_length_and_dec_int();
  return false;
}


bool Type_handler_real_result::
       Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
{
  item->fix_length_and_dec_double();
  return false;
}


bool Type_handler_decimal_result::
       Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
{
  item->fix_length_and_dec_decimal();
  return false;
}


bool Type_handler_temporal_result::
       Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
{
  item->fix_length_and_dec_temporal(true);
  return false;
}


bool Type_handler_string_result::
       Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
{
  item->fix_length_and_dec_double();
  return false;
}

/***************************************************************************/

const Vers_type_handler* Type_handler_temporal_result::vers() const
{
  return &vers_type_timestamp;
}

const Vers_type_handler* Type_handler_string_result::vers() const
{
  return &vers_type_timestamp;
}

const Vers_type_handler* Type_handler_blob_common::vers() const

{
  return &vers_type_timestamp;
}

/***************************************************************************/

uint Type_handler::Item_time_precision(THD *thd, Item *item) const
{
  return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}


uint Type_handler::Item_datetime_precision(THD *thd, Item *item) const
{
  return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}


uint Type_handler_string_result::Item_temporal_precision(THD *thd, Item *item,
                                                         bool is_time) const
{
  StringBuffer<64> buf;
  String *tmp;
  MYSQL_TIME_STATUS status;
  DBUG_ASSERT(item->is_fixed());
  // Nanosecond rounding is not needed here, for performance purposes
  if ((tmp= item->val_str(&buf)) &&
      (is_time ?
       Time(thd, &status, tmp->ptr(), tmp->length(), tmp->charset(),
            Time::Options(TIME_TIME_ONLY, TIME_FRAC_TRUNCATE,
                          Time::DATETIME_TO_TIME_YYYYMMDD_TRUNCATE)).
         is_valid_time() :
       Datetime(thd, &status, tmp->ptr(), tmp->length(), tmp->charset(),
                Datetime::Options(TIME_FUZZY_DATES, TIME_FRAC_TRUNCATE)).
         is_valid_datetime()))
    return MY_MIN(status.precision, TIME_SECOND_PART_DIGITS);
  return MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}

/***************************************************************************/

uint Type_handler::Item_decimal_scale(const Item *item) const
{
  return item->decimals < NOT_FIXED_DEC ?
         item->decimals :
         MY_MIN(item->max_length, DECIMAL_MAX_SCALE);
}

uint Type_handler_temporal_result::
       Item_decimal_scale_with_seconds(const Item *item) const
{
  return item->decimals < NOT_FIXED_DEC ?
         item->decimals :
         TIME_SECOND_PART_DIGITS;
}

uint Type_handler::Item_divisor_precision_increment(const Item *item) const
{
  return item->decimals;
}

uint Type_handler_temporal_result::
       Item_divisor_precision_increment_with_seconds(const Item *item) const
{
  return item->decimals <  NOT_FIXED_DEC ?
         item->decimals :
         TIME_SECOND_PART_DIGITS;
}

/***************************************************************************/

uint Type_handler_string_result::Item_decimal_precision(const Item *item) const
{
  uint res= item->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;
}

uint Type_handler_real_result::Item_decimal_precision(const Item *item) const
{
  uint res= item->max_char_length();
  return res ? MY_MIN(res, DECIMAL_MAX_PRECISION) : 1;
}

uint Type_handler_decimal_result::Item_decimal_precision(const Item *item) const
{
  uint prec= my_decimal_length_to_precision(item->max_char_length(),
                                            item->decimals,
                                            item->unsigned_flag);
  return MY_MIN(prec, DECIMAL_MAX_PRECISION);
}

uint Type_handler_int_result::Item_decimal_precision(const Item *item) const
{
 uint prec= my_decimal_length_to_precision(item->max_char_length(),
                                           item->decimals,
                                           item->unsigned_flag);
 return MY_MIN(prec, DECIMAL_MAX_PRECISION);
}

uint Type_handler_time_common::Item_decimal_precision(const Item *item) const
{
  return 7 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}

uint Type_handler_date_common::Item_decimal_precision(const Item *item) const
{
  return 8;
}

uint Type_handler_datetime_common::Item_decimal_precision(const Item *item) const
{
  return 14 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}

uint Type_handler_timestamp_common::Item_decimal_precision(const Item *item) const
{
  return 14 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS);
}

/***************************************************************************/

bool Type_handler_real_result::
       subquery_type_allows_materialization(const Item *inner,
                                            const Item *outer) const
{
  DBUG_ASSERT(inner->cmp_type() == REAL_RESULT);
  return outer->cmp_type() == REAL_RESULT;
}


bool Type_handler_int_result::
       subquery_type_allows_materialization(const Item *inner,
                                            const Item *outer) const
{
  DBUG_ASSERT(inner->cmp_type() == INT_RESULT);
  return outer->cmp_type() == INT_RESULT;
}


bool Type_handler_decimal_result::
       subquery_type_allows_materialization(const Item *inner,
                                            const Item *outer) const
{
  DBUG_ASSERT(inner->cmp_type() == DECIMAL_RESULT);
  return outer->cmp_type() == DECIMAL_RESULT;
}


bool Type_handler_string_result::
       subquery_type_allows_materialization(const Item *inner,
                                            const Item *outer) const
{
  DBUG_ASSERT(inner->cmp_type() == STRING_RESULT);
  return outer->cmp_type() == STRING_RESULT &&
         outer->collation.collation == inner->collation.collation &&
         /*
           Materialization also is unable to work when create_tmp_table() will
           create a blob column because item->max_length is too big.
           The following test is copied from varstring_type_handler().
         */
         !inner->too_big_for_varchar();
}


bool Type_handler_temporal_result::
       subquery_type_allows_materialization(const Item *inner,
                                            const Item *outer) const
{
  DBUG_ASSERT(inner->cmp_type() == TIME_RESULT);
  return mysql_timestamp_type() ==
         outer->type_handler()->mysql_timestamp_type();
}

/***************************************************************************/


const Type_handler *
Type_handler_null::type_handler_for_tmp_table(const Item *item) const
{
  return &type_handler_string;
}


const Type_handler *
Type_handler_null::type_handler_for_union(const Item *item) const
{
  return &type_handler_string;
}


const Type_handler *
Type_handler_olddecimal::type_handler_for_tmp_table(const Item *item) const
{
  return &type_handler_newdecimal;
}

const Type_handler *
Type_handler_olddecimal::type_handler_for_union(const Item *item) const
{
  return &type_handler_newdecimal;
}


/***************************************************************************/

bool Type_handler::check_null(const Item *item, st_value *value) const
{
  if (item->null_value)
  {
    value->m_type= DYN_COL_NULL;
    return true;
  }
  return false;
}


bool Type_handler_null::
       Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
  value->m_type= DYN_COL_NULL;
  return true;
}


bool Type_handler_row::
       Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
  DBUG_ASSERT(0);
  value->m_type= DYN_COL_NULL;
  return true;
}


bool Type_handler_int_result::
       Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
  value->m_type= item->unsigned_flag ? DYN_COL_UINT : DYN_COL_INT;
  value->value.m_longlong= item->val_int();
  return check_null(item, value);
}


bool Type_handler_real_result::
       Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
  value->m_type= DYN_COL_DOUBLE;
  value->value.m_double= item->val_real();
  return check_null(item, value);
}


bool Type_handler_decimal_result::
       Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
  value->m_type= DYN_COL_DECIMAL;
  my_decimal *dec= item->val_decimal(&value->m_decimal);
  if (dec != &value->m_decimal && !item->null_value)
    my_decimal2decimal(dec, &value->m_decimal);
  return check_null(item, value);
}


bool Type_handler_string_result::
       Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
  value->m_type= DYN_COL_STRING;
  String *str= item->val_str(&value->m_string);
  if (str != &value->m_string && !item->null_value)
    value->m_string.set(str->ptr(), str->length(), str->charset());
  return check_null(item, value);
}


bool Type_handler_temporal_with_date::
       Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
  value->m_type= DYN_COL_DATETIME;
  item->get_date(thd, &value->value.m_time,
                 Datetime::Options(thd, TIME_FRAC_NONE));
  return check_null(item, value);
}


bool Type_handler_time_common::
       Item_save_in_value(THD *thd, Item *item, st_value *value) const
{
  value->m_type= DYN_COL_DATETIME;
  item->get_time(thd, &value->value.m_time);
  return check_null(item, value);
}

/***************************************************************************/

bool Type_handler_row::
  Item_param_set_from_value(THD *thd,
                            Item_param *param,
                            const Type_all_attributes *attr,
                            const st_value *val) const
{
  DBUG_ASSERT(0);
  param->set_null();
  return true;
}


bool Type_handler_real_result::
  Item_param_set_from_value(THD *thd,
                            Item_param *param,
                            const Type_all_attributes *attr,
                            const st_value *val) const
{
  param->unsigned_flag= attr->unsigned_flag;
  param->set_double(val->value.m_double);
  return false;
}


bool Type_handler_int_result::
  Item_param_set_from_value(THD *thd,
                            Item_param *param,
                            const Type_all_attributes *attr,
                            const st_value *val) const
{
  param->unsigned_flag= attr->unsigned_flag;
  param->set_int(val->value.m_longlong, attr->max_length);
  return false;
}


bool Type_handler_decimal_result::
  Item_param_set_from_value(THD *thd,
                            Item_param *param,
                            const Type_all_attributes *attr,
                            const st_value *val) const
{
  param->unsigned_flag= attr->unsigned_flag;
  param->set_decimal(&val->m_decimal, attr->unsigned_flag);
  return false;
}


bool Type_handler_string_result::
  Item_param_set_from_value(THD *thd,
                            Item_param *param,
                            const Type_all_attributes *attr,
                            const st_value *val) const
{
  param->unsigned_flag= false;
  param->setup_conversion_string(thd, attr->collation.collation);
  /*
    Exact value of max_length is not known unless data is converted to
    charset of connection, so we have to set it later.
  */
  return param->set_str(val->m_string.ptr(), val->m_string.length(),
                        attr->collation.collation,
                        attr->collation.collation);
}


bool Type_handler_temporal_result::
  Item_param_set_from_value(THD *thd,
                            Item_param *param,
                            const Type_all_attributes *attr,
                            const st_value *val) const
{
  param->unsigned_flag= attr->unsigned_flag;
  param->set_time(&val->value.m_time, attr->max_length, attr->decimals);
  return false;
}


/***************************************************************************/

bool Type_handler_null::
      Item_send(Item *item, Protocol *protocol, st_value *buf) const
{
  return protocol->store_null();
}


bool Type_handler::
       Item_send_str(Item *item, Protocol *protocol, st_value *buf) const
{
  String *res;
  if ((res= item->val_str(&buf->m_string)))
  {
    DBUG_ASSERT(!item->null_value);
    return protocol->store(res->ptr(), res->length(), res->charset());
  }
  DBUG_ASSERT(item->null_value);
  return protocol->store_null();
}


bool Type_handler::
       Item_send_tiny(Item *item, Protocol *protocol, st_value *buf) const
{
  longlong nr= item->val_int();
  if (!item->null_value)
    return protocol->store_tiny(nr);
  return protocol->store_null();
}


bool Type_handler::
       Item_send_short(Item *item, Protocol *protocol, st_value *buf) const
{
  longlong nr= item->val_int();
  if (!item->null_value)
    return protocol->store_short(nr);
  return protocol->store_null();
}


bool Type_handler::
       Item_send_long(Item *item, Protocol *protocol, st_value *buf) const
{
  longlong nr= item->val_int();
  if (!item->null_value)
    return protocol->store_long(nr);
  return protocol->store_null();
}

bool Type_handler::
       Item_send_longlong(Item *item, Protocol *protocol, st_value *buf) const
{
  longlong nr= item->val_int();
  if (!item->null_value)
    return protocol->store_longlong(nr, item->unsigned_flag);
  return protocol->store_null();
}


bool Type_handler::
       Item_send_float(Item *item, Protocol *protocol, st_value *buf) const
{
  float nr= (float) item->val_real();
  if (!item->null_value)
    return protocol->store_float(nr, item->decimals);
  return protocol->store_null();
}


bool Type_handler::
       Item_send_double(Item *item, Protocol *protocol, st_value *buf) const
{
  double nr= item->val_real();
  if (!item->null_value)
    return protocol->store_double(nr, item->decimals);
  return protocol->store_null();
}


bool Type_handler::Item_send_timestamp(Item *item,
                                       Protocol *protocol,
                                       st_value *buf) const
{
  Timestamp_or_zero_datetime_native_null native(protocol->thd, item);
  if (native.is_null())
    return protocol->store_null();
  native.to_TIME(protocol->thd, &buf->value.m_time);
  return protocol->store(&buf->value.m_time, item->decimals);
}


bool Type_handler::
       Item_send_datetime(Item *item, Protocol *protocol, st_value *buf) const
{
  item->get_date(protocol->thd, &buf->value.m_time,
                 Datetime::Options(protocol->thd));
  if (!item->null_value)
    return protocol->store(&buf->value.m_time, item->decimals);
  return protocol->store_null();
}


bool Type_handler::
       Item_send_date(Item *item, Protocol *protocol, st_value *buf) const
{
  item->get_date(protocol->thd, &buf->value.m_time,
                 Date::Options(protocol->thd));
  if (!item->null_value)
    return protocol->store_date(&buf->value.m_time);
  return protocol->store_null();
}


bool Type_handler::
       Item_send_time(Item *item, Protocol *protocol, st_value *buf) const
{
  item->get_time(protocol->thd, &buf->value.m_time);
  if (!item->null_value)
    return protocol->store_time(&buf->value.m_time, item->decimals);
  return protocol->store_null();
}

/***************************************************************************/

Item *Type_handler_int_result::
  make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
  longlong result= item->val_int();
  if (item->null_value)
    return new (thd->mem_root) Item_null(thd, item->name.str);
  return  new (thd->mem_root) Item_int(thd, item->name.str, result,
                                       item->max_length);
}


Item *Type_handler_real_result::
  make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
  double result= item->val_real();
  if (item->null_value)
    return new (thd->mem_root) Item_null(thd, item->name.str);
  return new (thd->mem_root) Item_float(thd, item->name.str, result,
                                        item->decimals, item->max_length);
}


Item *Type_handler_decimal_result::
  make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
  VDec result(item);
  if (result.is_null())
    return new (thd->mem_root) Item_null(thd, item->name.str);
  return new (thd->mem_root) Item_decimal(thd, item->name.str, result.ptr(),
                                          item->max_length, item->decimals);
}


Item *Type_handler_string_result::
  make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
  StringBuffer<MAX_FIELD_WIDTH> tmp;
  String *result= item->val_str(&tmp);
  if (item->null_value)
    return new (thd->mem_root) Item_null(thd, item->name.str);
  LEX_CSTRING value;
  thd->make_lex_string(&value, result->ptr(), result->length());
  return new (thd->mem_root) Item_string(thd, item->name, value,
                                         result->charset());
}


Item *Type_handler_time_common::
  make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
  Item_cache_temporal *cache;
  longlong value= item->val_time_packed(thd);
  if (item->null_value)
    return new (thd->mem_root) Item_null(thd, item->name.str);
  cache= new (thd->mem_root) Item_cache_time(thd);
  if (cache)
    cache->store_packed(value, item);
  return cache;
}


Item *Type_handler_temporal_with_date::
  make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
  Item_cache_temporal *cache;
  longlong value= item->val_datetime_packed(thd);
  if (item->null_value)
    return new (thd->mem_root) Item_null(thd, item->name.str);
  cache= new (thd->mem_root) Item_cache_datetime(thd);
  if (cache)
    cache->store_packed(value, item);
  return cache;
}


Item *Type_handler_row::
  make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
{
  if (item->type() == Item::ROW_ITEM && cmp->type() == Item::ROW_ITEM)
  {
    /*
      Substitute constants only in Item_row's. Don't affect other Items
      with ROW_RESULT (eg Item_singlerow_subselect).

      For such Items more optimal is to detect if it is constant and replace
      it with Item_row. This would optimize queries like this:
      SELECT * FROM t1 WHERE (a,b) = (SELECT a,b FROM t2 LIMIT 1);
    */
    Item_row *item_row= (Item_row*) item;
    Item_row *comp_item_row= (Item_row*) cmp;
    uint col;
    /*
      If item and comp_item are both Item_row's and have same number of cols
      then process items in Item_row one by one.
      We can't ignore NULL values here as this item may be used with <=>, in
      which case NULL's are significant.
    */
    DBUG_ASSERT(item->result_type() == cmp->result_type());
    DBUG_ASSERT(item_row->cols() == comp_item_row->cols());
    col= item_row->cols();
    while (col-- > 0)
      resolve_const_item(thd, item_row->addr(col),
                         comp_item_row->element_index(col));
  }
  return NULL;
}

/***************************************************************************/

static const char* item_name(Item *a, String *str)
{
  if (a->name.str)
    return a->name.str;
  str->length(0);
  a->print(str, QT_ORDINARY);
  return str->c_ptr_safe();
}


static void wrong_precision_error(uint errcode, Item *a,
                                  ulonglong number, uint maximum)
{
  StringBuffer<1024> buf(system_charset_info);
  my_error(errcode, MYF(0), number, item_name(a, &buf), maximum);
}


/**
  Get precision and scale for a declaration
 
  return
    0  ok
    1  error
*/

bool get_length_and_scale(ulonglong length, ulonglong decimals,
                          uint *out_length, uint *out_decimals,
                          uint max_precision, uint max_scale,
                          Item *a)
{
  if (length > (ulonglong) max_precision)
  {
    wrong_precision_error(ER_TOO_BIG_PRECISION, a, length, max_precision);
    return 1;
  }
  if (decimals > (ulonglong) max_scale)
  {
    wrong_precision_error(ER_TOO_BIG_SCALE, a, decimals, max_scale);
    return 1;
  }

  *out_decimals=  (uint) decimals;
  my_decimal_trim(&length, out_decimals);
  *out_length=  (uint) length;
  
  if (*out_length < *out_decimals)
  {
    my_error(ER_M_BIGGER_THAN_D, MYF(0), "");
    return 1;
  }
  return 0;
}


Item *Type_handler_longlong::
        create_typecast_item(THD *thd, Item *item,
                             const Type_cast_attributes &attr) const
{
  if (this != &type_handler_ulonglong)
    return new (thd->mem_root) Item_func_signed(thd, item);
  return new (thd->mem_root) Item_func_unsigned(thd, item);

}


Item *Type_handler_date_common::
        create_typecast_item(THD *thd, Item *item,
                             const Type_cast_attributes &attr) const
{
  return new (thd->mem_root) Item_date_typecast(thd, item);
}



Item *Type_handler_time_common::
        create_typecast_item(THD *thd, Item *item,
                             const Type_cast_attributes &attr) const
{
  if (attr.decimals() > MAX_DATETIME_PRECISION)
  {
    wrong_precision_error(ER_TOO_BIG_PRECISION, item, attr.decimals(),
                          MAX_DATETIME_PRECISION);
    return 0;
  }
  return new (thd->mem_root)
         Item_time_typecast(thd, item, (uint) attr.decimals());
}


Item *Type_handler_datetime_common::
        create_typecast_item(THD *thd, Item *item,
                             const Type_cast_attributes &attr) const
{
  if (attr.decimals() > MAX_DATETIME_PRECISION)
  {
    wrong_precision_error(ER_TOO_BIG_PRECISION, item, attr.decimals(),
                          MAX_DATETIME_PRECISION);
    return 0;
  }
  return new (thd->mem_root)
         Item_datetime_typecast(thd, item, (uint) attr.decimals());

}


Item *Type_handler_decimal_result::
        create_typecast_item(THD *thd, Item *item,
                             const Type_cast_attributes &attr) const
{
  uint len, dec;
  if (get_length_and_scale(attr.length(), attr.decimals(), &len, &dec,
                           DECIMAL_MAX_PRECISION, DECIMAL_MAX_SCALE, item))
    return NULL;
  return new (thd->mem_root) Item_decimal_typecast(thd, item, len, dec);
}


Item *Type_handler_double::
        create_typecast_item(THD *thd, Item *item,
                             const Type_cast_attributes &attr) const
{
  uint len, dec;
  if (!attr.length_specified())
    return new (thd->mem_root) Item_double_typecast(thd, item,
                                                    DBL_DIG + 7,
                                                    NOT_FIXED_DEC);

  if (get_length_and_scale(attr.length(), attr.decimals(), &len, &dec,
                           DECIMAL_MAX_PRECISION, NOT_FIXED_DEC - 1, item))
    return NULL;
  return new (thd->mem_root) Item_double_typecast(thd, item, len, dec);
}


Item *Type_handler_float::
        create_typecast_item(THD *thd, Item *item,
                             const Type_cast_attributes &attr) const
{
  DBUG_ASSERT(!attr.length_specified());
  return new (thd->mem_root) Item_float_typecast(thd, item);
}


Item *Type_handler_long_blob::
        create_typecast_item(THD *thd, Item *item,
                             const Type_cast_attributes &attr) const
{
  int len= -1;
  CHARSET_INFO *real_cs= attr.charset() ?
                         attr.charset() :
                         thd->variables.collation_connection;
  if (attr.length_specified())
  {
    if (attr.length() > MAX_FIELD_BLOBLENGTH)
    {
      char buff[1024];
      String buf(buff, sizeof(buff), system_charset_info);
      my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), item_name(item, &buf),
               MAX_FIELD_BLOBLENGTH);
      return NULL;
    }
    len= (int) attr.length();
  }
  return new (thd->mem_root) Item_char_typecast(thd, item, len, real_cs);
}

Item *Type_handler_interval_DDhhmmssff::
        create_typecast_item(THD *thd, Item *item,
                             const Type_cast_attributes &attr) const
{
  if (attr.decimals() > MAX_DATETIME_PRECISION)
  {
    wrong_precision_error(ER_TOO_BIG_PRECISION, item, attr.decimals(),
                          MAX_DATETIME_PRECISION);
    return 0;
  }
  return new (thd->mem_root) Item_interval_DDhhmmssff_typecast(thd, item,
                                                               (uint)
                                                               attr.decimals());
}

/***************************************************************************/

void Type_handler_string_result::Item_param_setup_conversion(THD *thd,
                                                             Item_param *param)
                                                             const
{
  param->setup_conversion_string(thd, thd->variables.character_set_client);
}


void Type_handler_blob_common::Item_param_setup_conversion(THD *thd,
                                                           Item_param *param)
                                                           const
{
  param->setup_conversion_blob(thd);
}


void Type_handler_tiny::Item_param_set_param_func(Item_param *param,
                                                  uchar **pos, ulong len) const
{
  param->set_param_tiny(pos, len);
}


void Type_handler_short::Item_param_set_param_func(Item_param *param,
                                                   uchar **pos, ulong len) const
{
  param->set_param_short(pos, len);
}


void Type_handler_long::Item_param_set_param_func(Item_param *param,
                                                  uchar **pos, ulong len) const
{
  param->set_param_int32(pos, len);
}


void Type_handler_longlong::Item_param_set_param_func(Item_param *param,
                                                      uchar **pos,
                                                      ulong len) const
{
  param->set_param_int64(pos, len);
}


void Type_handler_float::Item_param_set_param_func(Item_param *param,
                                                   uchar **pos,
                                                   ulong len) const
{
  param->set_param_float(pos, len);
}


void Type_handler_double::Item_param_set_param_func(Item_param *param,
                                                   uchar **pos,
                                                   ulong len) const
{
  param->set_param_double(pos, len);
}


void Type_handler_decimal_result::Item_param_set_param_func(Item_param *param,
                                                            uchar **pos,
                                                            ulong len) const
{
  param->set_param_decimal(pos, len);
}


void Type_handler_string_result::Item_param_set_param_func(Item_param *param,
                                                           uchar **pos,
                                                           ulong len) const
{
  param->set_param_str(pos, len);
}


void Type_handler_time_common::Item_param_set_param_func(Item_param *param,
                                                         uchar **pos,
                                                         ulong len) const
{
  param->set_param_time(pos, len);
}


void Type_handler_date_common::Item_param_set_param_func(Item_param *param,
                                                         uchar **pos,
                                                         ulong len) const
{
  param->set_param_date(pos, len);
}


void Type_handler_datetime_common::Item_param_set_param_func(Item_param *param,
                                                             uchar **pos,
                                                             ulong len) const
{
  param->set_param_datetime(pos, len);
}

Field *Type_handler_blob_common::make_conversion_table_field(MEM_ROOT *root,
                                                            TABLE *table,
                                                            uint metadata,
                                                            const Field *target)
                                                            const
{
  uint pack_length= metadata & 0x00ff;
  if (pack_length < 1 || pack_length > 4)
    return NULL; // Broken binary log?
  return new(root)
         Field_blob(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str,
                    table->s, pack_length, target->charset());
}


void Type_handler_timestamp_common::Item_param_set_param_func(Item_param *param,
                                                              uchar **pos,
                                                              ulong len) const
{
  param->set_param_datetime(pos, len);
}


void Type_handler::Item_param_set_param_func(Item_param *param,
                                             uchar **pos,
                                             ulong len) const
{
  param->set_null(); // Not possible type code in the client-server protocol
}


void Type_handler_typelib::Item_param_set_param_func(Item_param *param,
                                                     uchar **pos,
                                                     ulong len) const
{
  param->set_null(); // Not possible type code in the client-server protocol
}


/***************************************************************************/

Field *Type_handler_row::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  DBUG_ASSERT(attr->length == 0);
  DBUG_ASSERT(f_maybe_null(attr->pack_flag));
  return new (mem_root) Field_row(rec.ptr(), name);
}


Field *Type_handler_olddecimal::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
  return new (mem_root)
    Field_decimal(rec.ptr(), (uint32) attr->length,
                  rec.null_ptr(), rec.null_bit(),
                  attr->unireg_check, name,
                  (uint8) attr->decimals,
                  f_is_zerofill(attr->pack_flag) != 0,
                  f_is_dec(attr->pack_flag) == 0);
}


Field *Type_handler_newdecimal::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
  return new (mem_root)
    Field_new_decimal(rec.ptr(), (uint32) attr->length,
                      rec.null_ptr(), rec.null_bit(),
                      attr->unireg_check, name,
                      (uint8) attr->decimals,
                      f_is_zerofill(attr->pack_flag) != 0,
                      f_is_dec(attr->pack_flag) == 0);
}


Field *Type_handler_float::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
  uint decimals= attr->decimals;
  if (decimals == FLOATING_POINT_DECIMALS)
    decimals= NOT_FIXED_DEC;
  return new (mem_root)
    Field_float(rec.ptr(), (uint32) attr->length,
                rec.null_ptr(), rec.null_bit(),
                attr->unireg_check, name, decimals,
                f_is_zerofill(attr->pack_flag) != 0,
                f_is_dec(attr->pack_flag)== 0);
}


Field *Type_handler_double::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  DBUG_ASSERT(f_decimals(attr->pack_flag) == 0);
  uint decimals= attr->decimals;
  if (decimals == FLOATING_POINT_DECIMALS)
    decimals= NOT_FIXED_DEC;
  return new (mem_root)
    Field_double(rec.ptr(), (uint32) attr->length,
                 rec.null_ptr(), rec.null_bit(),
                 attr->unireg_check, name, decimals,
                 f_is_zerofill(attr->pack_flag) != 0,
                 f_is_dec(attr->pack_flag)== 0);
}


Field *Type_handler_tiny::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  return new (mem_root)
    Field_tiny(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
               attr->unireg_check, name,
               f_is_zerofill(attr->pack_flag) != 0,
               f_is_dec(attr->pack_flag) == 0);
}


Field *Type_handler_short::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  return new (mem_root)
    Field_short(rec.ptr(), (uint32) attr->length,
                rec.null_ptr(), rec.null_bit(),
                attr->unireg_check, name,
                f_is_zerofill(attr->pack_flag) != 0,
                f_is_dec(attr->pack_flag) == 0);
}


Field *Type_handler_int24::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  return new (mem_root)
    Field_medium(rec.ptr(), (uint32) attr->length,
                 rec.null_ptr(), rec.null_bit(),
                 attr->unireg_check, name,
                 f_is_zerofill(attr->pack_flag) != 0,
                 f_is_dec(attr->pack_flag) == 0);
}


Field *Type_handler_long::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  return new (mem_root)
    Field_long(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
               attr->unireg_check, name,
               f_is_zerofill(attr->pack_flag) != 0,
               f_is_dec(attr->pack_flag) == 0);
}


Field *Type_handler_longlong::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  if (flags & (VERS_SYS_START_FLAG|VERS_SYS_END_FLAG))
    return new (mem_root)
      Field_vers_trx_id(rec.ptr(), (uint32) attr->length,
                        rec.null_ptr(), rec.null_bit(),
                        attr->unireg_check, name,
                        f_is_zerofill(attr->pack_flag) != 0,
                        f_is_dec(attr->pack_flag) == 0);
  return new (mem_root)
    Field_longlong(rec.ptr(), (uint32) attr->length,
                   rec.null_ptr(), rec.null_bit(),
                   attr->unireg_check, name,
                   f_is_zerofill(attr->pack_flag) != 0,
                   f_is_dec(attr->pack_flag) == 0);
}


Field *Type_handler_timestamp::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
  return new_Field_timestamp(mem_root,
                             rec.ptr(), rec.null_ptr(), rec.null_bit(),
                             attr->unireg_check, name, share,
                             attr->temporal_dec(MAX_DATETIME_WIDTH));
}


Field *Type_handler_timestamp2::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
  return new (mem_root)
    Field_timestampf(rec.ptr(), rec.null_ptr(), rec.null_bit(),
                     attr->unireg_check,
                     name, share, attr->temporal_dec(MAX_DATETIME_WIDTH));
}


Field *Type_handler_year::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                                   uint32 flags) const
{
  return new (mem_root)
    Field_year(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
               attr->unireg_check, name);
}


Field *Type_handler_date::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  return new (mem_root)
    Field_date(rec.ptr(),rec.null_ptr(),rec.null_bit(),
               attr->unireg_check, name);
}


Field *Type_handler_newdate::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  return new (mem_root)
    Field_newdate(rec.ptr(), rec.null_ptr(), rec.null_bit(),
                  attr->unireg_check, name);
}


Field *Type_handler_time::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  DBUG_ASSERT(attr->decimals == attr->temporal_dec(MIN_TIME_WIDTH));
  return new_Field_time(mem_root, rec.ptr(), rec.null_ptr(), rec.null_bit(),
                        attr->unireg_check, name,
                        attr->temporal_dec(MIN_TIME_WIDTH));
}


Field *Type_handler_time2::
  make_table_field_from_def(TABLE_SHARE *share,  MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  DBUG_ASSERT(attr->decimals == attr->temporal_dec(MIN_TIME_WIDTH));
  return new (mem_root)
    Field_timef(rec.ptr(), rec.null_ptr(), rec.null_bit(),
                attr->unireg_check, name,
                attr->temporal_dec(MIN_TIME_WIDTH));
}


Field *Type_handler_datetime::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
  return new_Field_datetime(mem_root, rec.ptr(), rec.null_ptr(), rec.null_bit(),
                            attr->unireg_check, name,
                            attr->temporal_dec(MAX_DATETIME_WIDTH));
}


Field *Type_handler_datetime2::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  DBUG_ASSERT(attr->decimals == attr->temporal_dec(MAX_DATETIME_WIDTH));
  return new (mem_root)
    Field_datetimef(rec.ptr(), rec.null_ptr(), rec.null_bit(),
                    attr->unireg_check, name,
                    attr->temporal_dec(MAX_DATETIME_WIDTH));
}


Field *Type_handler_null::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  return new (mem_root)
    Field_null(rec.ptr(), (uint32) attr->length, attr->unireg_check,
               name, attr->charset);
}


Field *Type_handler_bit::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  return f_bit_as_char(attr->pack_flag) ?
     new (mem_root) Field_bit_as_char(rec.ptr(), (uint32) attr->length,
                                      rec.null_ptr(), rec.null_bit(),
                                      attr->unireg_check, name) :
     new (mem_root) Field_bit(rec.ptr(), (uint32) attr->length,
                              rec.null_ptr(), rec.null_bit(),
                              bit.ptr(), bit.offs(), attr->unireg_check, name);
}




Field *Type_handler_string::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  return new (mem_root)
    Field_string(rec.ptr(), (uint32) attr->length,
                 rec.null_ptr(), rec.null_bit(),
                 attr->unireg_check, name, attr->charset);
}


Field *Type_handler_varchar::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  if (attr->unireg_check == Field::TMYSQL_COMPRESSED)
    return new (mem_root)
      Field_varstring_compressed(rec.ptr(), (uint32) attr->length,
                                 HA_VARCHAR_PACKLENGTH((uint32) attr->length),
                                 rec.null_ptr(), rec.null_bit(),
                                 attr->unireg_check, name, share, attr->charset,
                                 zlib_compression_method);
  return new (mem_root)
    Field_varstring(rec.ptr(), (uint32) attr->length,
                    HA_VARCHAR_PACKLENGTH((uint32) attr->length),
                    rec.null_ptr(), rec.null_bit(),
                    attr->unireg_check, name, share, attr->charset);
}


Field *Type_handler_blob_common::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  if (attr->unireg_check == Field::TMYSQL_COMPRESSED)
    return new (mem_root)
      Field_blob_compressed(rec.ptr(), rec.null_ptr(), rec.null_bit(),
                            attr->unireg_check, name, share,
                            attr->pack_flag_to_pack_length(), attr->charset,
                            zlib_compression_method);
  return new (mem_root)
    Field_blob(rec.ptr(), rec.null_ptr(), rec.null_bit(),
               attr->unireg_check, name, share,
               attr->pack_flag_to_pack_length(), attr->charset);
}


Field *Type_handler_enum::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  return new (mem_root)
    Field_enum(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
               attr->unireg_check, name, attr->pack_flag_to_pack_length(),
               attr->interval, attr->charset);
}


Field *Type_handler_set::
  make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
                            const LEX_CSTRING *name,
                            const Record_addr &rec, const Bit_addr &bit,
                            const Column_definition_attributes *attr,
                            uint32 flags) const
{
  return new (mem_root)
    Field_set(rec.ptr(), (uint32) attr->length, rec.null_ptr(), rec.null_bit(),
              attr->unireg_check, name, attr->pack_flag_to_pack_length(),
              attr->interval, attr->charset);
}


/***************************************************************************/

void Type_handler::
  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                        uchar *buff) const
{
  def->frm_pack_basic(buff);
  def->frm_pack_charset(buff);
}


void Type_handler_real_result::
  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                        uchar *buff) const
{
  def->frm_pack_numeric_with_dec(buff);
}


void Type_handler_decimal_result::
  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                        uchar *buff) const
{
  def->frm_pack_numeric_with_dec(buff);
}


void Type_handler_int_result::
  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                        uchar *buff) const
{
  DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
  DBUG_ASSERT(def->decimals == 0);
  Type_handler::Column_definition_attributes_frm_pack(def, buff);
}


void Type_handler_date_common::
  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                        uchar *buff) const
{
  DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
  DBUG_ASSERT(def->decimals == 0);
  Type_handler::Column_definition_attributes_frm_pack(def, buff);
}


void Type_handler_bit::
  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                        uchar *buff) const
{
  DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_TREAT_BIT_AS_CHAR) == 0);
  DBUG_ASSERT(def->decimals == 0);
  Type_handler::Column_definition_attributes_frm_pack(def, buff);
}


void Type_handler_blob_common::
  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                        uchar *buff) const
{
  DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_BLOB) == 0);
  DBUG_ASSERT(def->decimals == 0 ||
              def->decimals == NOT_FIXED_DEC);
  Type_handler::Column_definition_attributes_frm_pack(def, buff);
}


void Type_handler_null::
  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                        uchar *buff) const
{
  DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
  DBUG_ASSERT(def->decimals == NOT_FIXED_DEC);
  Type_handler::Column_definition_attributes_frm_pack(def, buff);
}


void Type_handler_string_result::
  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                        uchar *buff) const
{
  DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
  DBUG_ASSERT(def->decimals == 0 || def->decimals == NOT_FIXED_DEC);
  Type_handler::Column_definition_attributes_frm_pack(def, buff);
}


void Type_handler_enum::
  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                        uchar *buff) const
{
  DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_INTERVAL) == 0);
  DBUG_ASSERT(def->decimals == 0);
  Type_handler::Column_definition_attributes_frm_pack(def, buff);
}


void Type_handler_set::
  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                        uchar *buff) const
{
  DBUG_ASSERT(f_decimals(def->pack_flag & ~FIELDFLAG_BITFIELD) == 0);
  DBUG_ASSERT(def->decimals == 0);
  Type_handler::Column_definition_attributes_frm_pack(def, buff);
}


void Type_handler_temporal_result::
  Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
                                        uchar *buff) const
{
  DBUG_ASSERT(f_decimals(def->pack_flag) == 0);
  Type_handler::Column_definition_attributes_frm_pack(def, buff);
}


/***************************************************************************/

bool Type_handler::
  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
                                          TABLE_SHARE *share,
                                          const uchar *buffer,
                                          LEX_CUSTRING *gis_options)
                                          const
{
  attr->frm_unpack_basic(buffer);
  return attr->frm_unpack_charset(share, buffer);
}


bool Type_handler_real_result::
  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
                                          TABLE_SHARE *share,
                                          const uchar *buffer,
                                          LEX_CUSTRING *gis_options)
                                          const
{
  return attr->frm_unpack_numeric_with_dec(share, buffer);
}


bool Type_handler_decimal_result::
  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
                                          TABLE_SHARE *share,
                                          const uchar *buffer,
                                          LEX_CUSTRING *gis_options)
                                          const
{
  return attr->frm_unpack_numeric_with_dec(share, buffer);
}


bool Type_handler_time_common::
  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
                                          TABLE_SHARE *share,
                                          const uchar *buffer,
                                          LEX_CUSTRING *gis_options)
                                          const
{
  return attr->frm_unpack_temporal_with_dec(share, MIN_TIME_WIDTH, buffer);
}


bool Type_handler_datetime_common::
  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
                                          TABLE_SHARE *share,
                                          const uchar *buffer,
                                          LEX_CUSTRING *gis_options)
                                          const
{
  return attr->frm_unpack_temporal_with_dec(share, MAX_DATETIME_WIDTH, buffer);
}


bool Type_handler_timestamp_common::
  Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
                                          TABLE_SHARE *share,
                                          const uchar *buffer,
                                          LEX_CUSTRING *gis_options)
                                          const
{
  return attr->frm_unpack_temporal_with_dec(share, MAX_DATETIME_WIDTH, buffer);
}


bool Type_handler_null::Item_const_eq(const Item_const *a,
                                      const Item_const *b,
                                      bool binary_cmp) const
{
  return true;
}


bool Type_handler_real_result::Item_const_eq(const Item_const *a,
                                             const Item_const *b,
                                             bool binary_cmp) const
{
  const double *va= a->const_ptr_double();
  const double *vb= b->const_ptr_double();
  return va[0] == vb[0];
}


bool Type_handler_int_result::Item_const_eq(const Item_const *a,
                                            const Item_const *b,
                                            bool binary_cmp) const
{
  const longlong *va= a->const_ptr_longlong();
  const longlong *vb= b->const_ptr_longlong();
  bool res= va[0] == vb[0] &&
            (va[0] >= 0 ||
             (a->get_type_all_attributes_from_const()->unsigned_flag ==
              b->get_type_all_attributes_from_const()->unsigned_flag));
  return res;
}


bool Type_handler_string_result::Item_const_eq(const Item_const *a,
                                               const Item_const *b,
                                               bool binary_cmp) const
{
  const String *sa= a->const_ptr_string();
  const String *sb= b->const_ptr_string();
  return binary_cmp ? sa->bin_eq(sb) :
    a->get_type_all_attributes_from_const()->collation.collation ==
    b->get_type_all_attributes_from_const()->collation.collation &&
    sa->eq(sb, a->get_type_all_attributes_from_const()->collation.collation);
}


bool
Type_handler_decimal_result::Item_const_eq(const Item_const *a,
                                           const Item_const *b,
                                           bool binary_cmp) const
{
  const my_decimal *da= a->const_ptr_my_decimal();
  const my_decimal *db= b->const_ptr_my_decimal();
  return !da->cmp(db) &&
         (!binary_cmp ||
          a->get_type_all_attributes_from_const()->decimals ==
          b->get_type_all_attributes_from_const()->decimals);
}


bool
Type_handler_temporal_result::Item_const_eq(const Item_const *a,
                                            const Item_const *b,
                                            bool binary_cmp) const
{
  const MYSQL_TIME *ta= a->const_ptr_mysql_time();
  const MYSQL_TIME *tb= b->const_ptr_mysql_time();
  return !my_time_compare(ta, tb) &&
         (!binary_cmp ||
          a->get_type_all_attributes_from_const()->decimals ==
          b->get_type_all_attributes_from_const()->decimals);
}

/***************************************************************************/

const Type_handler *
Type_handler_hex_hybrid::cast_to_int_type_handler() const
{
  return &type_handler_ulonglong;
}


/***************************************************************************/

bool Type_handler_row::Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
                                     Item *a, Item *b) const
{
  DBUG_ASSERT(0);
  return false;
}


bool Type_handler_int_result::Item_eq_value(THD *thd,
                                            const Type_cmp_attributes *attr,
                                            Item *a, Item *b) const
{
  longlong value0= a->val_int();
  longlong value1= b->val_int();
  return !a->null_value && !b->null_value && value0 == value1 &&
         (value0 >= 0 || a->unsigned_flag == b->unsigned_flag);
}


bool Type_handler_real_result::Item_eq_value(THD *thd,
                                             const Type_cmp_attributes *attr,
                                             Item *a, Item *b) const
{
  double value0= a->val_real();
  double value1= b->val_real();
  return !a->null_value && !b->null_value && value0 == value1;
}


bool Type_handler_time_common::Item_eq_value(THD *thd,
                                             const Type_cmp_attributes *attr,
                                             Item *a, Item *b) const
{
  longlong value0= a->val_time_packed(thd);
  longlong value1= b->val_time_packed(thd);
  return !a->null_value && !b->null_value && value0 == value1;
}


bool Type_handler_temporal_with_date::Item_eq_value(THD *thd,
                                                    const Type_cmp_attributes *attr,
                                                    Item *a, Item *b) const
{
  longlong value0= a->val_datetime_packed(thd);
  longlong value1= b->val_datetime_packed(thd);
  return !a->null_value && !b->null_value && value0 == value1;
}


bool Type_handler_timestamp_common::Item_eq_value(THD *thd,
                                                  const Type_cmp_attributes *attr,
                                                  Item *a, Item *b) const
{
  Timestamp_or_zero_datetime_native_null na(thd, a, true);
  Timestamp_or_zero_datetime_native_null nb(thd, b, true);
  return !na.is_null() && !nb.is_null() && !cmp_native(na, nb);
}


bool Type_handler_string_result::Item_eq_value(THD *thd,
                                               const Type_cmp_attributes *attr,
                                               Item *a, Item *b) const
{
  String *va, *vb;
  StringBuffer<128> cmp_value1, cmp_value2;
  return (va= a->val_str(&cmp_value1)) &&
         (vb= b->val_str(&cmp_value2)) &&
          va->eq(vb, attr->compare_collation());
}


/***************************************************************************/

bool Type_handler_string_result::union_element_finalize(const Item * item) const
{
  if (item->collation.derivation == DERIVATION_NONE)
  {
    my_error(ER_CANT_AGGREGATE_NCOLLATIONS, MYF(0), "UNION");
    return true;
  }
  return false;
}


/***************************************************************************/

void Type_handler_var_string::
  Column_definition_implicit_upgrade(Column_definition *c) const
{
  // Change old VARCHAR to new VARCHAR
  c->set_handler(&type_handler_varchar);
}


void Type_handler_time_common::
  Column_definition_implicit_upgrade(Column_definition *c) const
{
  if (opt_mysql56_temporal_format)
    c->set_handler(&type_handler_time2);
  else
    c->set_handler(&type_handler_time);
}


void Type_handler_datetime_common::
  Column_definition_implicit_upgrade(Column_definition *c) const
{
  if (opt_mysql56_temporal_format)
    c->set_handler(&type_handler_datetime2);
  else
    c->set_handler(&type_handler_datetime);
}


void Type_handler_timestamp_common::
  Column_definition_implicit_upgrade(Column_definition *c) const
{
  if (opt_mysql56_temporal_format)
    c->set_handler(&type_handler_timestamp2);
  else
    c->set_handler(&type_handler_timestamp);
}


/***************************************************************************/


int Type_handler_temporal_with_date::stored_field_cmp_to_item(THD *thd,
                                                              Field *field,
                                                              Item *item) const
{
  MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time;
  field->get_date(&field_time, Datetime::Options(TIME_INVALID_DATES, thd));
  item->get_date(thd, &item_time, Datetime::Options(TIME_INVALID_DATES, thd));
  if (item_time.time_type == MYSQL_TIMESTAMP_TIME &&
      time_to_datetime(thd, &item_time, item_time_cmp= &item_time2))
    return 1;
  return my_time_compare(&field_time, item_time_cmp);
}


int Type_handler_time_common::stored_field_cmp_to_item(THD *thd,
                                                       Field *field,
                                                       Item *item) const
{
  MYSQL_TIME field_time, item_time;
  field->get_date(&field_time, Time::Options(thd));
  item->get_date(thd, &item_time, Time::Options(thd));
  return my_time_compare(&field_time, &item_time);
}


int Type_handler_string_result::stored_field_cmp_to_item(THD *thd,
                                                         Field *field,
                                                         Item *item) const
{
  StringBuffer<MAX_FIELD_WIDTH> item_tmp;
  StringBuffer<MAX_FIELD_WIDTH> field_tmp;
  String *item_result= item->val_str(&item_tmp);
  /*
    Some implementations of Item::val_str(String*) actually modify
    the field Item::null_value, hence we can't check it earlier.
  */
  if (item->null_value)
    return 0;
  String *field_result= field->val_str(&field_tmp);
  return sortcmp(field_result, item_result, field->charset());
}


int Type_handler_int_result::stored_field_cmp_to_item(THD *thd,
                                                      Field *field,
                                                      Item *item) const
{
  DBUG_ASSERT(0); // Not used yet
  return 0;
}


int Type_handler_real_result::stored_field_cmp_to_item(THD *thd,
                                                       Field *field,
                                                       Item *item) const
{
  /*
    The patch for Bug#13463415 started using this function for comparing
    BIGINTs. That uncovered a bug in Visual Studio 32bit optimized mode.
    Prefixing the auto variables with volatile fixes the problem....
  */
  volatile double result= item->val_real();
  if (item->null_value)
    return 0;
  volatile double field_result= field->val_real();
  if (field_result < result)
    return -1;
  else if (field_result > result)
    return 1;
  return 0;
}


/***************************************************************************/


static bool have_important_literal_warnings(const MYSQL_TIME_STATUS *status)
{
  return (status->warnings & ~MYSQL_TIME_NOTE_TRUNCATED) != 0;
}


static void literal_warn(THD *thd, const Item *item,
                         const char *str, size_t length, CHARSET_INFO *cs,
                         const MYSQL_TIME_STATUS *st,
                         const char *typestr, bool send_error)
{
  if (likely(item))
  {
    if (st->warnings) // e.g. a note on nanosecond truncation
    {
      ErrConvString err(str, length, cs);
      thd->push_warning_wrong_or_truncated_value(
                                   Sql_condition::time_warn_level(st->warnings),
                                   false, typestr, err.ptr(),
                                   nullptr, nullptr, nullptr);
    }
  }
  else if (send_error)
  {
    ErrConvString err(str, length, cs);
    my_error(ER_WRONG_VALUE, MYF(0), typestr, err.ptr());
  }
}


Item_literal *
Type_handler_date_common::create_literal_item(THD *thd,
                                              const char *str,
                                              size_t length,
                                              CHARSET_INFO *cs,
                                              bool send_error) const
{
  Temporal::Warn st;
  Item_literal *item= NULL;
  Temporal_hybrid tmp(thd, &st, str, length, cs, Temporal_hybrid::Options(thd));
  if (tmp.is_valid_temporal() &&
      tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATE &&
      !have_important_literal_warnings(&st))
  {
    Date d(&tmp);
    item= new (thd->mem_root) Item_date_literal(thd, &d);
  }
  literal_warn(thd, item, str, length, cs, &st, "DATE", send_error);
  return item;
}


Item_literal *
Type_handler_temporal_with_date::create_literal_item(THD *thd,
                                                     const char *str,
                                                     size_t length,
                                                     CHARSET_INFO *cs,
                                                     bool send_error) const
{
  Temporal::Warn st;
  Item_literal *item= NULL;
  Temporal_hybrid tmp(thd, &st, str, length, cs, Temporal_hybrid::Options(thd));
  if (tmp.is_valid_temporal() &&
      tmp.get_mysql_time()->time_type == MYSQL_TIMESTAMP_DATETIME &&
      !have_important_literal_warnings(&st))
  {
    Datetime dt(&tmp);
    item= new (thd->mem_root) Item_datetime_literal(thd, &dt, st.precision);
  }
  literal_warn(thd, item, str, length, cs, &st, "DATETIME", send_error);
  return item;
}


Item_literal *
Type_handler_time_common::create_literal_item(THD *thd,
                                              const char *str,
                                              size_t length,
                                              CHARSET_INFO *cs,
                                              bool send_error) const
{
  MYSQL_TIME_STATUS st;
  Item_literal *item= NULL;
  Time::Options opt(TIME_TIME_ONLY, thd, Time::DATETIME_TO_TIME_DISALLOW);
  Time tmp(thd, &st, str, length, cs, opt);
  if (tmp.is_valid_time() &&
      !have_important_literal_warnings(&st))
    item= new (thd->mem_root) Item_time_literal(thd, &tmp, st.precision);
  literal_warn(thd, item, str, length, cs, &st, "TIME", send_error);
  return item;
}


bool
Type_handler_time_common::Item_val_native_with_conversion(THD *thd,
                                                          Item *item,
                                                          Native *to) const
{
  if (item->type_handler()->type_handler_for_native_format() ==
      &type_handler_time2)
    return item->val_native(thd, to);
  return Time(thd, item).to_native(to, item->time_precision(thd));
}


bool
Type_handler_time_common::Item_val_native_with_conversion_result(THD *thd,
                                                                 Item *item,
                                                                 Native *to)
                                                                 const
{
  if (item->type_handler()->type_handler_for_native_format() ==
      &type_handler_time2)
    return item->val_native_result(thd, to);
  MYSQL_TIME ltime;
  if (item->get_date_result(thd, &ltime, Time::Options(thd)))
    return true;
  int warn;
  return Time(&warn, &ltime, 0).to_native(to, item->time_precision(thd));
}


int Type_handler_time_common::cmp_native(const Native &a,
                                         const Native &b) const
{
  // Optimize a simple case: equal fractional precision:
  if (a.length() == b.length())
    return memcmp(a.ptr(), b.ptr(), a.length());
  longlong lla= Time(a).to_packed();
  longlong llb= Time(b).to_packed();
  if (lla < llb)
    return -1;
  if (lla> llb)
    return 1;
  return 0;
}


bool Type_handler_timestamp_common::TIME_to_native(THD *thd,
                                                   const MYSQL_TIME *ltime,
                                                   Native *to,
                                                   uint decimals) const
{
  uint error_code;
  Timestamp_or_zero_datetime tm(thd, ltime, &error_code);
  if (error_code)
    return true;
  tm.trunc(decimals);
  return tm.to_native(to, decimals);
}


bool
Type_handler_timestamp_common::Item_val_native_with_conversion(THD *thd,
                                                               Item *item,
                                                               Native *to) const
{
  MYSQL_TIME ltime;
  if (item->type_handler()->type_handler_for_native_format() ==
      &type_handler_timestamp2)
    return item->val_native(thd, to);
  return
    item->get_date(thd, &ltime, Datetime::Options(TIME_NO_ZERO_IN_DATE, thd)) ||
    TIME_to_native(thd, &ltime, to, item->datetime_precision(thd));
}


bool
Type_handler_timestamp_common::Item_val_native_with_conversion_result(THD *thd,
                                                                      Item *item,
                                                                      Native *to)
                                                                      const
{
  MYSQL_TIME ltime;
  if (item->type_handler()->type_handler_for_native_format() ==
      &type_handler_timestamp2)
    return item->val_native_result(thd, to);
  return
    item->get_date_result(thd, &ltime,
                          Datetime::Options(TIME_NO_ZERO_IN_DATE, thd)) ||
    TIME_to_native(thd, &ltime, to, item->datetime_precision(thd));
}


int Type_handler_timestamp_common::cmp_native(const Native &a,
                                              const Native &b) const
{
  /*
    Optimize a simple case:
    Either both timeatamp values have the same fractional precision,
    or both values are zero datetime '0000-00-00 00:00:00.000000',
  */
  if (a.length() == b.length())
    return memcmp(a.ptr(), b.ptr(), a.length());
  return Timestamp_or_zero_datetime(a).cmp(Timestamp_or_zero_datetime(b));
}


Timestamp_or_zero_datetime_native_null::
  Timestamp_or_zero_datetime_native_null(THD *thd, Item *item, bool conv)
   :Null_flag(false)
{
  DBUG_ASSERT(item->type_handler()->type_handler_for_native_format() ==
              &type_handler_timestamp2 || conv);
  if (conv ?
      type_handler_timestamp2.Item_val_native_with_conversion(thd, item, this) :
      item->val_native(thd, this))
    Null_flag::operator=(true);
  // If no conversion, then is_null() should be equal to item->null_value
  DBUG_ASSERT(is_null() == item->null_value || conv);
  /*
    is_null() can be true together with item->null_value==false, which means
    a non-NULL item was evaluated, but then the conversion to TIMESTAMP failed.
    But is_null() can never be false if item->null_value==true.
  */
  DBUG_ASSERT(is_null() >= item->null_value);
}


bool
Type_handler::Item_param_val_native(THD *thd,
                                        Item_param *item,
                                        Native *to) const
{
  DBUG_ASSERT(0); // TODO-TYPE: MDEV-14271
  return item->null_value= true;
}


bool
Type_handler_timestamp_common::Item_param_val_native(THD *thd,
                                                         Item_param *item,
                                                         Native *to) const
{
  /*
    The below code may not run well in corner cases.
    This will be fixed under terms of MDEV-14271.
    Item_param should:
    - either remember @@time_zone at bind time
    - or store TIMESTAMP in my_time_t format, rather than in MYSQL_TIME format.
  */
  MYSQL_TIME ltime;
  return
    item->get_date(thd, &ltime, Datetime::Options(TIME_NO_ZERO_IN_DATE, thd)) ||
    TIME_to_native(thd, &ltime, to, item->datetime_precision(thd));
}


bool
Type_handler_time_common::Item_param_val_native(THD *thd,
                                                Item_param *item,
                                                Native *to) const
{
  return Time(thd, item).to_native(to, item->decimals);
}


/***************************************************************************/

bool Type_handler::validate_implicit_default_value(THD *thd,
                                       const Column_definition &def) const
{
  DBUG_EXECUTE_IF("validate_implicit_default_value_error", return true;);
  return false;
}


bool Type_handler_date_common::validate_implicit_default_value(THD *thd,
                                       const Column_definition &def) const
{
  return thd->variables.sql_mode & MODE_NO_ZERO_DATE;
}


bool Type_handler_datetime_common::validate_implicit_default_value(THD *thd,
                                       const Column_definition &def) const
{
  return thd->variables.sql_mode & MODE_NO_ZERO_DATE;
}


/***************************************************************************/

const Name & Type_handler_row::default_value() const
{
  DBUG_ASSERT(0);
  static Name def(STRING_WITH_LEN(""));
  return def;
}

const Name & Type_handler_numeric::default_value() const
{
  static Name def(STRING_WITH_LEN("0"));
  return def;
}

const Name & Type_handler_string_result::default_value() const
{
  static Name def(STRING_WITH_LEN(""));
  return def;
}

const Name & Type_handler_time_common::default_value() const
{
  static Name def(STRING_WITH_LEN("00:00:00"));
  return def;
}

const Name & Type_handler_date_common::default_value() const
{
  static Name def(STRING_WITH_LEN("0000-00-00"));
  return def;
}

const Name & Type_handler_datetime_common::default_value() const
{
  static Name def(STRING_WITH_LEN("0000-00-00 00:00:00"));
  return def;
}

const Name & Type_handler_timestamp_common::default_value() const
{
  static Name def(STRING_WITH_LEN("0000-00-00 00:00:00"));
  return def;
}

/***************************************************************************/

bool Type_handler::Column_definition_data_type_info_image(Binary_string *to,
                                                   const Column_definition &def)
                                                   const
{
  // Have *some* columns write type info (let's use string fields as an example)
  DBUG_EXECUTE_IF("frm_data_type_info_emulate",
                  if (cmp_type() == STRING_RESULT)
                    return to->append("x", 1) ||
                           to->append(name().lex_cstring()););
  if (type_collection() != &type_collection_std)
    return to->append(name().lex_cstring());
  return false;
}


/***************************************************************************/

void
Type_handler::partition_field_type_not_allowed(const LEX_CSTRING &field_name)
{
  my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0),
           field_name.str);
}


bool
Type_handler::partition_field_check_result_type(Item *item,
                                                Item_result expected_type)
{
  if (item->result_type() != expected_type)
  {
    my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
    return TRUE;
  }
  return false;
}


bool
Type_handler_blob_common::partition_field_check(const LEX_CSTRING &field_name,
                                                Item *item_expr) const
{
  my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0));
  return true;
}


bool
Type_handler_general_purpose_int::partition_field_append_value(
                                            String *str,
                                            Item *item_expr,
                                            CHARSET_INFO *field_cs,
                                            partition_value_print_mode_t mode)
                                            const
{
  DBUG_ASSERT(item_expr->cmp_type() == INT_RESULT);
  StringBuffer<21> tmp;
  longlong value= item_expr->val_int();
  tmp.set(value, system_charset_info);
  return str->append(tmp);
}


/*
  Append an Item value to a String using a desired mode.

  @param [OUT] str          The string to append the value to.
  @param       item_expr    The item to get the value from
  @param       field_cs     The character set of the value owner field.
  @param       mode         The mode.
  @retval      true         on error
  @retval      false        on success

  The value is added using system_charset_info (no matter what mode is).

 (1) If mode is equal to PARTITION_VALUE_PRINT_MODE_FRM,
     the value is appended as a pure ASCII string in the format '_latin1 0xdf',
     i.e. a character set introducer followed by a hex hybrid.

     Before appending, we value is first converted to field_cs.
     a) If the conversion succeeds, the value is printed in its field_cs
        represenation.
     b) If the conversion fails, the value is printed without conversion,
        using the original character set introducer followed by the original
        string hex representation.
        In this case, open_table_from_share() will later notice that
        the value cannot be actually stored to the field, and report
        the error. So here we don't need to report errors such as
        ER_PARTITION_FUNCTION_IS_NOT_ALLOWED.

 (2) If the mode is equal to PARTITION_VALUE_PRINT_SHOW,
     then the value is needed for:
     - SHOW CREATE TABLE, or
     - the PARTITION_DESCRIPTION column in a
       INFORMATION_SCHEMA.PARTITION query.

     The value generated here will be later sent to the client and
     therefore will be converted to the client character set in the protocol.

     We try to generate the value as a simple quoted utf8 string without
     introducers (e.g. 'utf8-string') when possible, to make it:
     - as human readable as possible
     - but still safe for mysqldump purposes.

     Simple quoted utf8 string is generated when these two conditions are true
     at the same time:
       a) The value can be safely converted to utf8,
          so we can return it without data loss from this function.
       b) The value can be safely converted to the client character set,
          so we can convert it later without data loss to the client character
          set in the protocol.

     If one of the conditions fail, the value is returned using
     PARTITION_VALUE_PRINT_MODE_FRM representation. See (1).
*/
bool Type_handler::partition_field_append_value(
                                            String *str,
                                            Item *item_expr,
                                            CHARSET_INFO *field_cs,
                                            partition_value_print_mode_t mode)
                                            const
{
  DBUG_ASSERT(cmp_type() != INT_RESULT);
  StringBuffer<MAX_KEY_LENGTH> buf;
  String *res;

  if (!(res= item_expr->val_str(&buf)))
    return str->append(STRING_WITH_LEN("NULL"), system_charset_info);

  if (!res->length())
    return str->append(STRING_WITH_LEN("''"), system_charset_info);

  if (mode == PARTITION_VALUE_PRINT_MODE_FRM ||
      !res->can_be_safely_converted_to(current_thd->
                                         variables.character_set_client) ||
      !res->can_be_safely_converted_to(system_charset_info))
  {
    StringBuffer<64> buf2;
    uint cnverr2= 0;
    buf2.copy(res->ptr(), res->length(), res->charset(), field_cs, &cnverr2);
    if (!cnverr2)
      return str->append_introducer_and_hex(&buf2);
    return str->append_introducer_and_hex(res);
  }

  StringBuffer<64> val(system_charset_info);
  uint cnverr= 0;
  val.copy(res->ptr(), res->length(), res->charset(),
           system_charset_info, &cnverr);
  append_unescaped(str, val.ptr(), val.length());
  return false;
}


bool Type_handler::can_return_extract_source(interval_type int_type) const
{
  return type_collection() == &type_collection_std;
}

/***************************************************************************/

LEX_CSTRING Charset::collation_specific_name() const
{
  /*
    User defined collations can provide arbitrary names
    for character sets and collations, so a collation
    name not necessarily starts with the character set name.
  */
  size_t csname_length= strlen(m_charset->csname);
  if (strncmp(m_charset->name, m_charset->csname, csname_length))
    return {NULL, 0};
  const char *ptr= m_charset->name + csname_length;
  return {ptr, strlen(ptr) };
}


bool
Charset::encoding_allows_reinterpret_as(const CHARSET_INFO *cs) const
{
  if (!strcmp(m_charset->csname, cs->csname))
    return true;

  if (!strcmp(m_charset->csname, MY_UTF8MB3) &&
      !strcmp(cs->csname, MY_UTF8MB4))
    return true;

  /*
    Originally we allowed here instat ALTER for ASCII-to-LATIN1
    and UCS2-to-UTF16, but this was wrong:
    - MariaDB's ascii is not a subset for 8-bit character sets
      like latin1, because it allows storing bytes 0x80..0xFF as
      "unassigned" characters (see MDEV-19285).
    - MariaDB's ucs2 (as in Unicode-1.1) is not a subset for UTF16,
      because they treat surrogate codes differently (MDEV-19284).
  */
  return false;
}


bool
Charset::eq_collation_specific_names(CHARSET_INFO *cs) const
{
  LEX_CSTRING name0= collation_specific_name();
  LEX_CSTRING name1= Charset(cs).collation_specific_name();
  return name0.length && !cmp(&name0, &name1);
}

int initialize_data_type_plugin(st_plugin_int *plugin)
{
  st_mariadb_data_type *data= (st_mariadb_data_type*) plugin->plugin->info;
  data->type_handler->set_name(Name(plugin->name));
  if (plugin->plugin->init && plugin->plugin->init(NULL))
  {
    sql_print_error("Plugin '%s' init function returned error.",
                    plugin->name.str);
    return 1;
  }
  return 0;
}
