static bool check_list_constants(THD *thd, partition_info *part_info)
{
  uint i, size_entries, num_column_values;
  uint list_index= 0;
  part_elem_value *list_value;
  bool result= TRUE;
  longlong type_add, calc_value;
  void *curr_value;
  void *UNINIT_VAR(prev_value);
  partition_element* part_def;
  bool found_null= FALSE;
  qsort_cmp compare_func;
  void *ptr;
  List_iterator<partition_element> list_func_it(part_info->partitions);
  DBUG_ENTER("check_list_constants");

  DBUG_ASSERT(part_info->part_type == LIST_PARTITION);

  part_info->num_list_values= 0;
  /*
    We begin by calculating the number of list values that have been
    defined in the first step.

    We use this number to allocate a properly sized array of structs
    to keep the partition id and the value to use in that partition.
    In the second traversal we assign them values in the struct array.

    Finally we sort the array of structs in order of values to enable
    a quick binary search for the proper value to discover the
    partition id.
    After sorting the array we check that there are no duplicates in the
    list.
  */

  i= 0;
  do
  {
    part_def= list_func_it++;
    if (part_def->has_null_value)
    {
      if (found_null)
      {
        my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
        goto end;
      }
      part_info->has_null_value= TRUE;
      part_info->has_null_part_id= i;
      found_null= TRUE;
    }
    part_info->num_list_values+= part_def->list_val_list.elements;
  } while (++i < part_info->num_parts);
  list_func_it.rewind();
  num_column_values= part_info->part_field_list.elements;
  size_entries= part_info->column_list ?
        (num_column_values * sizeof(part_column_list_val)) :
        sizeof(LIST_PART_ENTRY);
  if (!(ptr= thd->calloc((part_info->num_list_values+1) * size_entries)))
    goto end;
  if (part_info->column_list)
  {
    part_column_list_val *loc_list_col_array;
    loc_list_col_array= (part_column_list_val*)ptr;
    part_info->list_col_array= (part_column_list_val*)ptr;
    compare_func= partition_info_compare_column_values;
    i= 0;
    do
    {
      part_def= list_func_it++;
      if (part_def->max_value)
      {
        // DEFAULT is not a real value so let's exclude it from sorting.
        DBUG_ASSERT(part_info->num_list_values);
        part_info->num_list_values--;
        continue;
      }
      List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
      while ((list_value= list_val_it2++))
      {
        part_column_list_val *col_val= list_value->col_val_array;
        if (part_info->fix_column_value_functions(thd, list_value, i))
          DBUG_RETURN(result);
        memcpy(loc_list_col_array, (const void*)col_val, size_entries);
        loc_list_col_array+= num_column_values;
      }
    } while (++i < part_info->num_parts);
  }
  else
  {
    compare_func= partition_info_list_part_cmp;
    part_info->list_array= (LIST_PART_ENTRY*)ptr;
    i= 0;
    /*
      Fix to be able to reuse signed sort functions also for unsigned
      partition functions.
    */
    type_add= (longlong)(part_info->part_expr->unsigned_flag ?
                                       0x8000000000000000ULL :
                                       0ULL);

    do
    {
      part_def= list_func_it++;
      if (part_def->max_value)
      {
        // DEFAULT is not a real value so let's exclude it from sorting.
        DBUG_ASSERT(part_info->num_list_values);
        part_info->num_list_values--;
        continue;
      }
      List_iterator<part_elem_value> list_val_it2(part_def->list_val_list);
      while ((list_value= list_val_it2++))
      {
        calc_value= list_value->value - type_add;
        part_info->list_array[list_index].list_value= calc_value;
        part_info->list_array[list_index++].partition_id= i;
      }
    } while (++i < part_info->num_parts);
  }
  DBUG_ASSERT(part_info->fixed);
  if (part_info->num_list_values)
  {
    bool first= TRUE;
    /*
      list_array and list_col_array are unions, so this works for both
      variants of LIST partitioning.
    */
    my_qsort(part_info->list_array, part_info->num_list_values, size_entries,
             compare_func);

    i= 0;
    do
    {
      DBUG_ASSERT(i < part_info->num_list_values);
      curr_value= part_info->column_list
                  ? (void*)&part_info->list_col_array[num_column_values * i]
                  : (void*)&part_info->list_array[i];
      if (likely(first || compare_func(curr_value, prev_value)))
      {
        prev_value= curr_value;
        first= FALSE;
      }
      else
      {
        my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
        goto end;
      }
    } while (++i < part_info->num_list_values);
  }
  result= FALSE;
end:
  DBUG_RETURN(result);
}