bool Column_definition::check(THD *thd)
{
  const uint conditional_type_modifiers= AUTO_INCREMENT_FLAG;
  uint sign_len, allowed_type_modifier= 0;
  ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
  DBUG_ENTER("Column_definition::check");

  /* Initialize data for a computed field */
  if (vcol_info)
  {
    DBUG_ASSERT(vcol_info->expr);
    vcol_info->set_field_type(sql_type);
    if (check_expression(vcol_info, field_name, vcol_info->stored_in_db
                         ? VCOL_GENERATED_STORED : VCOL_GENERATED_VIRTUAL))
      DBUG_RETURN(TRUE);
  }

  if (check_constraint &&
      check_expression(check_constraint, field_name, VCOL_CHECK_FIELD))
      DBUG_RETURN(1);

  if (default_value)
  {
    Item *def_expr= default_value->expr;
    if (check_expression(default_value, field_name, VCOL_DEFAULT))
      DBUG_RETURN(TRUE);

    /* Constant's are stored in the 'empty_record', except for blobs */
    if (def_expr->basic_const_item())
    {
      if (def_expr->type() == Item::NULL_ITEM)
      {
        default_value= 0;
        if ((flags & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) == NOT_NULL_FLAG)
        {
          my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
          DBUG_RETURN(1);
        }
      }
    }
  }

  if (default_value && (flags & AUTO_INCREMENT_FLAG))
  {
    my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
    DBUG_RETURN(1);
  }

  if (default_value && !default_value->expr->basic_const_item() &&
      mysql_type_to_time_type(sql_type) == MYSQL_TIMESTAMP_DATETIME &&
      default_value->expr->type() == Item::FUNC_ITEM)
  {
    /*
      Special case: NOW() for TIMESTAMP and DATETIME fields are handled
      as in MariaDB 10.1 by marking them in unireg_check.
    */
    Item_func *fn= static_cast<Item_func*>(default_value->expr);
    if (fn->functype() == Item_func::NOW_FUNC &&
        (fn->decimals == 0 || fn->decimals >= length))
    {
      default_value= 0;
      unireg_check= Field::TIMESTAMP_DN_FIELD;
    }
  }

  if (on_update)
  {
    if (mysql_type_to_time_type(sql_type) != MYSQL_TIMESTAMP_DATETIME ||
        on_update->decimals < length)
    {
      my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name);
      DBUG_RETURN(TRUE);
    }
    unireg_check= unireg_check == Field::NONE ? Field::TIMESTAMP_UN_FIELD
                                              : Field::TIMESTAMP_DNUN_FIELD;
  }
  else if (flags & AUTO_INCREMENT_FLAG)
    unireg_check= Field::NEXT_NUMBER;

  sign_len= flags & UNSIGNED_FLAG ? 0 : 1;

  switch (sql_type) {
  case MYSQL_TYPE_TINY:
    if (!length)
      length= MAX_TINYINT_WIDTH+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case MYSQL_TYPE_SHORT:
    if (!length)
      length= MAX_SMALLINT_WIDTH+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case MYSQL_TYPE_INT24:
    if (!length)
      length= MAX_MEDIUMINT_WIDTH+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case MYSQL_TYPE_LONG:
    if (!length)
      length= MAX_INT_WIDTH+sign_len;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case MYSQL_TYPE_LONGLONG:
    if (!length)
      length= MAX_BIGINT_WIDTH;
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    break;
  case MYSQL_TYPE_NULL:
    break;
  case MYSQL_TYPE_NEWDECIMAL:
    if (decimals >= NOT_FIXED_DEC)
    {
      my_error(ER_TOO_BIG_SCALE, MYF(0), static_cast<ulonglong>(decimals),
               field_name, static_cast<uint>(NOT_FIXED_DEC - 1));
      DBUG_RETURN(TRUE);
    }
    my_decimal_trim(&length, &decimals);
    if (length > DECIMAL_MAX_PRECISION)
    {
      my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name,
               DECIMAL_MAX_PRECISION);
      DBUG_RETURN(TRUE);
    }
    if (length < decimals)
    {
      my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
      DBUG_RETURN(TRUE);
    }
    length=
      my_decimal_precision_to_length((uint)length, decimals, flags & UNSIGNED_FLAG);
    pack_length=
      my_decimal_get_binary_size((uint)length, decimals);
    break;
  case MYSQL_TYPE_VARCHAR:
    /*
      Long VARCHAR's are automatically converted to blobs in mysql_prepare_table
      if they don't have a default value
    */
    max_field_charlength= MAX_FIELD_VARCHARLENGTH;
    break;
  case MYSQL_TYPE_STRING:
    break;
  case MYSQL_TYPE_BLOB:
  case MYSQL_TYPE_TINY_BLOB:
  case MYSQL_TYPE_LONG_BLOB:
  case MYSQL_TYPE_MEDIUM_BLOB:
  case MYSQL_TYPE_GEOMETRY:
    flags|= BLOB_FLAG;
    break;
  case MYSQL_TYPE_YEAR:
    if (!length || length != 2)
      length= 4; /* Default length */
    flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
    break;
  case MYSQL_TYPE_FLOAT:
    /* change FLOAT(precision) to FLOAT or DOUBLE */
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    if (!length && !decimals)
    {
      length=  MAX_FLOAT_STR_LENGTH;
      decimals= NOT_FIXED_DEC;
    }
    if (length < decimals &&
        decimals != NOT_FIXED_DEC)
    {
      my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
      DBUG_RETURN(TRUE);
    }
    if (decimals != NOT_FIXED_DEC && decimals >= FLOATING_POINT_DECIMALS)
    {
      my_error(ER_TOO_BIG_SCALE, MYF(0), static_cast<ulonglong>(decimals),
               field_name, static_cast<uint>(FLOATING_POINT_DECIMALS-1));
      DBUG_RETURN(TRUE);
    }
    break;
  case MYSQL_TYPE_DOUBLE:
    allowed_type_modifier= AUTO_INCREMENT_FLAG;
    if (!length && !decimals)
    {
      length= DBL_DIG+7;
      decimals= NOT_FIXED_DEC;
    }
    if (length < decimals &&
        decimals != NOT_FIXED_DEC)
    {
      my_error(ER_M_BIGGER_THAN_D, MYF(0), field_name);
      DBUG_RETURN(TRUE);
    }
    if (decimals != NOT_FIXED_DEC && decimals >= FLOATING_POINT_DECIMALS)
    {
      my_error(ER_TOO_BIG_SCALE, MYF(0), static_cast<ulonglong>(decimals),
               field_name, static_cast<uint>(FLOATING_POINT_DECIMALS-1));
      DBUG_RETURN(TRUE);
    }
    break;
  case MYSQL_TYPE_TIMESTAMP:
  case MYSQL_TYPE_TIMESTAMP2:
    if (length > MAX_DATETIME_PRECISION)
    {
      my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name,
               MAX_DATETIME_PRECISION);
      DBUG_RETURN(TRUE);
    }
    length+= MAX_DATETIME_WIDTH + (length ? 1 : 0);
    flags|= UNSIGNED_FLAG;
    break;
  case MYSQL_TYPE_DATE:
    /* We don't support creation of MYSQL_TYPE_DATE anymore */
    sql_type= MYSQL_TYPE_NEWDATE;
    /* fall through */
  case MYSQL_TYPE_NEWDATE:
    length= MAX_DATE_WIDTH;
    break;
  case MYSQL_TYPE_TIME:
  case MYSQL_TYPE_TIME2:
    if (length > MAX_DATETIME_PRECISION)
    {
      my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name,
               MAX_DATETIME_PRECISION);
      DBUG_RETURN(TRUE);
    }
    length+= MIN_TIME_WIDTH + (length ? 1 : 0);
    break;
  case MYSQL_TYPE_DATETIME:
  case MYSQL_TYPE_DATETIME2:
    if (length > MAX_DATETIME_PRECISION)
    {
      my_error(ER_TOO_BIG_PRECISION, MYF(0), length, field_name,
               MAX_DATETIME_PRECISION);
      DBUG_RETURN(TRUE);
    }
    length+= MAX_DATETIME_WIDTH + (length ? 1 : 0);
    break;
  case MYSQL_TYPE_SET:
    pack_length= get_set_pack_length(interval_list.elements);
    break;
  case MYSQL_TYPE_ENUM:
    /* Should be safe. */
    pack_length= get_enum_pack_length(interval_list.elements);
    break;
  case MYSQL_TYPE_VAR_STRING:
    DBUG_ASSERT(0);  /* Impossible. */
    break;
  case MYSQL_TYPE_BIT:
    {
      if (!length)
        length= 1;
      if (length > MAX_BIT_FIELD_LENGTH)
      {
        my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name,
                 static_cast<ulong>(MAX_BIT_FIELD_LENGTH));
        DBUG_RETURN(TRUE);
      }
      pack_length= ((uint)length + 7) / 8;
      break;
    }
  case MYSQL_TYPE_DECIMAL:
    DBUG_ASSERT(0); /* Was obsolete */
  }
  /* Remember the value of length */
  char_length= (uint)length;

  /*
    Set NO_DEFAULT_VALUE_FLAG if this field doesn't have a default value and
    it is NOT NULL, not an AUTO_INCREMENT field.
    We need to do this check here and in mysql_create_prepare_table() as
    sp_head::fill_field_definition() calls this function.
  */
  if (!default_value && unireg_check == Field::NONE && (flags & NOT_NULL_FLAG))
  {
    /*
      TIMESTAMP columns get implicit DEFAULT value when
      explicit_defaults_for_timestamp is not set.
    */
    if (opt_explicit_defaults_for_timestamp ||
        !is_timestamp_type(sql_type))
    {
      flags|= NO_DEFAULT_VALUE_FLAG;
    }
  }

  if (!(flags & BLOB_FLAG) &&
      ((length > max_field_charlength &&
        sql_type != MYSQL_TYPE_VARCHAR) ||
       (length == 0 &&
        sql_type != MYSQL_TYPE_ENUM && sql_type != MYSQL_TYPE_SET &&
        sql_type != MYSQL_TYPE_STRING && sql_type != MYSQL_TYPE_VARCHAR &&
        sql_type != MYSQL_TYPE_GEOMETRY)))
  {
    my_error((sql_type == MYSQL_TYPE_VAR_STRING ||
              sql_type == MYSQL_TYPE_VARCHAR ||
              sql_type == MYSQL_TYPE_STRING) ?  ER_TOO_BIG_FIELDLENGTH :
                                                ER_TOO_BIG_DISPLAYWIDTH,
              MYF(0),
              field_name, max_field_charlength); /* purecov: inspected */
    DBUG_RETURN(TRUE);
  }
  else if (length > MAX_FIELD_BLOBLENGTH)
  {
    my_error(ER_TOO_BIG_DISPLAYWIDTH, MYF(0), field_name, MAX_FIELD_BLOBLENGTH);
    DBUG_RETURN(1);
  }

  if ((~allowed_type_modifier) & flags & conditional_type_modifiers)
  {
    my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
    DBUG_RETURN(TRUE);
  }

  DBUG_RETURN(FALSE); /* success */
}