static int get_part_iter_for_interval_via_mapping(partition_info *part_info,
                        bool is_subpart,
                        uint32 *store_length_array, /* ignored */
                        uchar *min_value, uchar *max_value,
                        uint min_len, uint max_len, /* ignored */
                        uint flags, PARTITION_ITERATOR *part_iter)
{
  Field *field= part_info->part_field_array[0];
  uint32             UNINIT_VAR(max_endpoint_val);
  get_endpoint_func  UNINIT_VAR(get_endpoint);
  bool               can_match_multiple_values;  /* is not '=' */
  uint field_len= field->pack_length_in_rec();
  MYSQL_TIME start_date;
  bool check_zero_dates= false;
  bool zero_in_start_date= true;
  DBUG_ENTER("get_part_iter_for_interval_via_mapping");
  DBUG_ASSERT(!is_subpart);
  (void) store_length_array;
  (void)min_len;
  (void)max_len;
  part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE;
  part_iter->ret_default_part= part_iter->ret_default_part_orig= FALSE;

  if (part_info->part_type == RANGE_PARTITION ||
      part_info->part_type == VERSIONING_PARTITION)
  {
    if (part_info->part_charset_field_array)
      get_endpoint=        get_partition_id_range_for_endpoint_charset;
    else
      get_endpoint=        get_partition_id_range_for_endpoint;
    max_endpoint_val=    part_info->num_parts;
    part_iter->get_next= get_next_partition_id_range;
  }
  else if (part_info->part_type == LIST_PARTITION)
  {

    if (part_info->part_charset_field_array)
      get_endpoint=        get_list_array_idx_for_endpoint_charset;
    else
      get_endpoint=        get_list_array_idx_for_endpoint;
    max_endpoint_val=    part_info->num_list_values;
    part_iter->get_next= get_next_partition_id_list;
    part_iter->part_info= part_info;
    if (max_endpoint_val == 0)
    {
      /*
        We handle this special case without optimisations since it is
        of little practical value but causes a great number of complex
        checks later in the code.
      */
      part_iter->part_nums.start= part_iter->part_nums.end= 0;
      part_iter->part_nums.cur= 0;
      part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
      DBUG_RETURN(-1);
    }
  }
  else
    MY_ASSERT_UNREACHABLE();

  can_match_multiple_values= ((flags &
                               (NO_MIN_RANGE | NO_MAX_RANGE | NEAR_MIN |
                                NEAR_MAX)) ||
                              memcmp(min_value, max_value, field_len));
  DBUG_ASSERT(can_match_multiple_values || (flags & EQ_RANGE) || flags == 0);
  if (can_match_multiple_values && part_info->has_default_partititon())
    part_iter->ret_default_part= part_iter->ret_default_part_orig= TRUE;
  if (can_match_multiple_values &&
      (part_info->part_type == RANGE_PARTITION ||
       part_info->has_null_value))
  {
    /* Range scan on RANGE or LIST partitioned table */
    enum_monotonicity_info monotonic;
    monotonic= part_info->part_expr->get_monotonicity_info();
    if (monotonic == MONOTONIC_INCREASING_NOT_NULL ||
        monotonic == MONOTONIC_STRICT_INCREASING_NOT_NULL)
    {
      /* col is NOT NULL, but F(col) can return NULL, add NULL partition */
      part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
      check_zero_dates= true;
    }
  }

  /* 
    Find minimum: Do special handling if the interval has left bound in form
     " NULL <= X ":
  */
  if (field->real_maybe_null() && part_info->has_null_value && 
      !(flags & (NO_MIN_RANGE | NEAR_MIN)) && *min_value)
  {
    part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
    part_iter->part_nums.start= part_iter->part_nums.cur= 0;
    if (!(flags & NO_MAX_RANGE) && *max_value)
    {
      /* The right bound is X <= NULL, i.e. it is a "X IS NULL" interval */
      part_iter->part_nums.end= 0;
      /*
        It is something like select * from tbl where col IS NULL
        and we have partition with NULL to catch it, so we do not need
        DEFAULT partition
      */
      part_iter->ret_default_part= part_iter->ret_default_part_orig= FALSE;
      DBUG_RETURN(1);
    }
  }
  else
  {
    if (flags & NO_MIN_RANGE)
      part_iter->part_nums.start= part_iter->part_nums.cur= 0;
    else
    {
      /*
        Store the interval edge in the record buffer, and call the
        function that maps the edge in table-field space to an edge
        in ordered-set-of-partitions (for RANGE partitioning) or 
        index-in-ordered-array-of-list-constants (for LIST) space.
      */
      store_key_image_to_rec(field, min_value, field_len);
      bool include_endp= !MY_TEST(flags & NEAR_MIN);
      part_iter->part_nums.start= get_endpoint(part_info, 1, include_endp);
      if (!can_match_multiple_values && part_info->part_expr->null_value)
      {
        /* col = x and F(x) = NULL -> only search NULL partition */
        part_iter->part_nums.cur= part_iter->part_nums.start= 0;
        part_iter->part_nums.end= 0;
        /*
          if NULL partition exists:
            for RANGE it is the first partition (always exists);
            for LIST should be indicator that it is present
        */
        if (part_info->part_type == RANGE_PARTITION ||
            part_info->has_null_value)
        {
          part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE;
          DBUG_RETURN(1);
        }
        // If no NULL partition look up in DEFAULT or there is no such value
        goto not_found;
      }
      part_iter->part_nums.cur= part_iter->part_nums.start;
      if (check_zero_dates && !part_info->part_expr->null_value)
      {
        if (!(flags & NO_MAX_RANGE) &&
            (field->type() == MYSQL_TYPE_DATE ||
             field->type() == MYSQL_TYPE_DATETIME))
        {
          /* Monotonic, but return NULL for dates with zeros in month/day. */
          zero_in_start_date= field->get_date(&start_date, 0);
          DBUG_PRINT("info", ("zero start %u %04d-%02d-%02d",
                              zero_in_start_date, start_date.year,
                              start_date.month, start_date.day));
        }
      }
      if (part_iter->part_nums.start == max_endpoint_val)
        goto not_found;
    }
  }

  /* Find maximum, do the same as above but for right interval bound */
  if (flags & NO_MAX_RANGE)
    part_iter->part_nums.end= max_endpoint_val;
  else
  {
    store_key_image_to_rec(field, max_value, field_len);
    bool include_endp= !MY_TEST(flags & NEAR_MAX);
    part_iter->part_nums.end= get_endpoint(part_info, 0, include_endp);
    if (check_zero_dates &&
        !zero_in_start_date &&
        !part_info->part_expr->null_value)
    {
      MYSQL_TIME end_date;
      bool zero_in_end_date= field->get_date(&end_date, 0);
      /*
        This is an optimization for TO_DAYS()/TO_SECONDS() to avoid scanning
        the NULL partition for ranges that cannot include a date with 0 as
        month/day.
      */
      DBUG_PRINT("info", ("zero end %u %04d-%02d-%02d",
                          zero_in_end_date,
                          end_date.year, end_date.month, end_date.day));
      DBUG_ASSERT(!memcmp(((Item_func*) part_info->part_expr)->func_name(),
                          "to_days", 7) ||
                  !memcmp(((Item_func*) part_info->part_expr)->func_name(),
                          "to_seconds", 10));
      if (!zero_in_end_date &&
          start_date.month == end_date.month &&
          start_date.year == end_date.year)
        part_iter->ret_null_part= part_iter->ret_null_part_orig= false;
    }
    if (part_iter->part_nums.start >= part_iter->part_nums.end &&
        !part_iter->ret_null_part)
      goto not_found;
  }
  DBUG_RETURN(1); /* Ok, iterator initialized */

not_found:
  if (part_info->has_default_partititon())
  {
    part_iter->ret_default_part= part_iter->ret_default_part_orig= TRUE;
    DBUG_RETURN(1);
  }
  DBUG_RETURN(0); /* No partitions */
}