Commit c1a3261e authored by unknown's avatar unknown
Browse files

Merge rburnett@bk-internal.mysql.com:/home/bk/mysql-5.1-new

into  linux.site:/home/reggie/work/mysql-5.1-bug17631


sql/ha_partition.cc:
  Auto merged
sql/sql_partition.cc:
  Auto merged
sql/sql_show.cc:
  Auto merged
sql/sql_table.cc:
  Auto merged
parents 29f50132 04570aa5
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -642,7 +642,7 @@ drop table t1;
create table t1 (a int) engine=innodb partition by hash(a) ;
show table status like 't1';
Name	Engine	Version	Row_format	Rows	Avg_row_length	Data_length	Max_data_length	Index_length	Data_free	Auto_increment	Create_time	Update_time	Check_time	Collation	Checksum	Create_options	Comment
t1	PARTITION	10	Compact	2	8192	16384	0	0	0	NULL	NULL	NULL	NULL	latin1_swedish_ci	NULL		
t1	InnoDB	10	Compact	2	8192	16384	0	0	0	NULL	NULL	NULL	NULL	latin1_swedish_ci	NULL	partitioned	
drop table t1;
create table t2 (s1 int not null auto_increment, primary key (s1)) partition by list (s1) (partition p1 values in (1),partition p2 values in (2),partition p3 values in (3),partition p4 values in (4));
insert into t2 values (null),(null),(null);
@@ -819,4 +819,14 @@ explain partitions select * from t1 where a is null or a < 0 or a > 1;
id	select_type	table	partitions	type	possible_keys	key	key_len	ref	rows	Extra
1	SIMPLE	t1	pn,p2	ALL	NULL	NULL	NULL	NULL	2	Using where
drop table t1;
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, name VARCHAR(20)) 
ENGINE=MyISAM DEFAULT CHARSET=latin1
PARTITION BY RANGE(id)
(PARTITION p0  VALUES LESS THAN (10) ENGINE = MyISAM,
PARTITION p1 VALUES LESS THAN (20) ENGINE = MyISAM,
PARTITION p2 VALUES LESS THAN (30) ENGINE = MyISAM);
SHOW TABLE STATUS;
Name	Engine	Version	Row_format	Rows	Avg_row_length	Data_length	Max_data_length	Index_length	Data_free	Auto_increment	Create_time	Update_time	Check_time	Collation	Checksum	Create_options	Comment
t1	MyISAM	10	Dynamic	0	0	0	0	0	0	NULL	NULL	NULL	NULL	latin1_swedish_ci	NULL	partitioned	
DROP TABLE t1;
End of 5.1 tests
+13 −0
Original line number Diff line number Diff line
@@ -924,4 +924,17 @@ select * from t1 where a is null or a < 0 or a > 1;
explain partitions select * from t1 where a is null or a < 0 or a > 1;
drop table t1;

#
#Bug# 17631 SHOW TABLE STATUS reports wrong engine
#
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, name VARCHAR(20)) 
ENGINE=MyISAM DEFAULT CHARSET=latin1
PARTITION BY RANGE(id)
(PARTITION p0  VALUES LESS THAN (10) ENGINE = MyISAM,
PARTITION p1 VALUES LESS THAN (20) ENGINE = MyISAM,
PARTITION p2 VALUES LESS THAN (30) ENGINE = MyISAM);
--replace_column 6 0 7 0 8 0 9 0 12 NULL 13 NULL 14 NULL
SHOW TABLE STATUS;
DROP TABLE t1;

--echo End of 5.1 tests
+7 −0
Original line number Diff line number Diff line
@@ -258,6 +258,13 @@ void ha_partition::init_handler_variables()
}


const char *ha_partition::table_type() const
{ 
  // we can do this since we only support a single engine type
  return m_file[0]->table_type(); 
}


/*
  Destructor method

+1 −2
Original line number Diff line number Diff line
@@ -524,8 +524,7 @@ class ha_partition :public handler
  virtual const char *index_type(uint inx);

  /* The name of the table type that will be used for display purposes */
  virtual const char *table_type() const
  { return "PARTITION"; }
  virtual const char *table_type() const;

  /* The name of the row type used for the underlying tables. */
  virtual enum row_type get_row_type() const;
+358 −3
Original line number Diff line number Diff line
@@ -124,7 +124,6 @@ char *partition_info::create_default_partition_names(uint part_no, uint no_parts

  SYNOPSIS
    set_up_default_partitions()
    part_info           The reference to all partition information
    file                A reference to a handler of the table
    max_rows            Maximum number of rows stored in the table
    start_no            Starting partition number
@@ -201,7 +200,6 @@ bool partition_info::set_up_default_partitions(handler *file, ulonglong max_rows

  SYNOPSIS
    set_up_default_subpartitions()
    part_info           The reference to all partition information
    file                A reference to a handler of the table
    max_rows            Maximum number of rows stored in the table

@@ -271,7 +269,6 @@ bool partition_info::set_up_default_subpartitions(handler *file,

  SYNOPSIS
    set_up_defaults_for_partitioning()
    part_info           The reference to all partition information
    file                A reference to a handler of the table
    max_rows            Maximum number of rows stored in the table
    start_no            Starting partition number
@@ -388,4 +385,362 @@ char *partition_info::has_unique_names()
  DBUG_RETURN(NULL);
}


/*
  Check that all partitions use the same storage engine.
  This is currently a limitation in this version.

  SYNOPSIS
    check_engine_mix()
    engine_array           An array of engine identifiers
    no_parts               Total number of partitions

  RETURN VALUE
    TRUE                   Error, mixed engines
    FALSE                  Ok, no mixed engines
  DESCRIPTION
    Current check verifies only that all handlers are the same.
    Later this check will be more sophisticated.
*/

bool partition_info::check_engine_mix(handlerton **engine_array, uint no_parts)
{
  uint i= 0;
  bool result= FALSE;
  DBUG_ENTER("partition_info::check_engine_mix");

  do
  {
    if (engine_array[i] != engine_array[0])
    {
      result= TRUE;
      break;
    }
  } while (++i < no_parts);
  DBUG_RETURN(result);
}


/*
  This routine allocates an array for all range constants to achieve a fast
  check what partition a certain value belongs to. At the same time it does
  also check that the range constants are defined in increasing order and
  that the expressions are constant integer expressions.

  SYNOPSIS
    check_range_constants()

  RETURN VALUE
    TRUE                An error occurred during creation of range constants
    FALSE               Successful creation of range constant mapping

  DESCRIPTION
    This routine is called from check_partition_info to get a quick error
    before we came too far into the CREATE TABLE process. It is also called
    from fix_partition_func every time we open the .frm file. It is only
    called for RANGE PARTITIONed tables.
*/

bool partition_info::check_range_constants()
{
  partition_element* part_def;
  longlong current_largest_int= LONGLONG_MIN;
  longlong part_range_value_int;
  uint i;
  List_iterator<partition_element> it(partitions);
  bool result= TRUE;
  DBUG_ENTER("partition_info::check_range_constants");
  DBUG_PRINT("enter", ("INT_RESULT with %d parts", no_parts));

  part_result_type= INT_RESULT;
  range_int_array= (longlong*)sql_alloc(no_parts * sizeof(longlong));
  if (unlikely(range_int_array == NULL))
  {
    mem_alloc_error(no_parts * sizeof(longlong));
    goto end;
  }
  i= 0;
  do
  {
    part_def= it++;
    if ((i != (no_parts - 1)) || !defined_max_value)
      part_range_value_int= part_def->range_value; 
    else
      part_range_value_int= LONGLONG_MAX;
    if (likely(current_largest_int < part_range_value_int))
    {
      current_largest_int= part_range_value_int;
      range_int_array[i]= part_range_value_int;
    }
    else
    {
      my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0));
      goto end;
    }
  } while (++i < no_parts);
  result= FALSE;
end:
  DBUG_RETURN(result);
}


/*
  A support routine for check_list_constants used by qsort to sort the
  constant list expressions.

  SYNOPSIS
    list_part_cmp()
      a                First list constant to compare with
      b                Second list constant to compare with

  RETURN VALUE
    +1                 a > b
    0                  a  == b
    -1                 a < b
*/

int partition_info::list_part_cmp(const void* a, const void* b)
{
  longlong a1= ((LIST_PART_ENTRY*)a)->list_value;
  longlong b1= ((LIST_PART_ENTRY*)b)->list_value;
  if (a1 < b1)
    return -1;
  else if (a1 > b1)
    return +1;
  else
    return 0;
}


/*
  This routine allocates an array for all list constants to achieve a fast
  check what partition a certain value belongs to. At the same time it does
  also check that there are no duplicates among the list constants and that
  that the list expressions are constant integer expressions.

  SYNOPSIS
    check_list_constants()

  RETURN VALUE
    TRUE                  An error occurred during creation of list constants
    FALSE                 Successful creation of list constant mapping

  DESCRIPTION
    This routine is called from check_partition_info to get a quick error
    before we came too far into the CREATE TABLE process. It is also called
    from fix_partition_func every time we open the .frm file. It is only
    called for LIST PARTITIONed tables.
*/

bool partition_info::check_list_constants()
{
  uint i;
  uint list_index= 0;
  longlong *list_value;
  bool not_first;
  bool result= TRUE;
  longlong curr_value, prev_value;
  partition_element* part_def;
  bool found_null= FALSE;
  List_iterator<partition_element> list_func_it(partitions);
  DBUG_ENTER("partition_info::check_list_constants");

  part_result_type= INT_RESULT;
  no_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;
      }
      has_null_value= TRUE;
      has_null_part_id= i;
      found_null= TRUE;
    }
    List_iterator<longlong> list_val_it1(part_def->list_val_list);
    while (list_val_it1++)
      no_list_values++;
  } while (++i < no_parts);
  list_func_it.rewind();
  list_array= (LIST_PART_ENTRY*)sql_alloc(no_list_values*sizeof(LIST_PART_ENTRY));
  if (unlikely(list_array == NULL))
  {
    mem_alloc_error(no_list_values * sizeof(LIST_PART_ENTRY));
    goto end;
  }

  i= 0;
  do
  {
    part_def= list_func_it++;
    List_iterator<longlong> list_val_it2(part_def->list_val_list);
    while ((list_value= list_val_it2++))
    {
      list_array[list_index].list_value= *list_value;
      list_array[list_index++].partition_id= i;
    }
  } while (++i < no_parts);

  qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY), 
        &list_part_cmp);

  not_first= FALSE;
  i= prev_value= 0; //prev_value initialised to quiet compiler
  do
  {
    curr_value= list_array[i].list_value;
    if (likely(!not_first || prev_value != curr_value))
    {
      prev_value= curr_value;
      not_first= TRUE;
    }
    else
    {
      my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0));
      goto end;
    }
  } while (++i < no_list_values);
  result= FALSE;
end:
  DBUG_RETURN(result);
}


/*
  This code is used early in the CREATE TABLE and ALTER TABLE process.

  SYNOPSIS
    check_partition_info()
    file                A reference to a handler of the table
    max_rows            Maximum number of rows stored in the table
    engine_type         Return value for used engine in partitions

  RETURN VALUE
    TRUE                 Error, something went wrong
    FALSE                Ok, full partition data structures are now generated

  DESCRIPTION
    We will check that the partition info requested is possible to set-up in
    this version. This routine is an extension of the parser one could say.
    If defaults were used we will generate default data structures for all
    partitions.

*/

bool partition_info::check_partition_info(handlerton **eng_type,
                                          handler *file, ulonglong max_rows)
{
  handlerton **engine_array= NULL;
  uint part_count= 0;
  uint i, tot_partitions;
  bool result= TRUE;
  char *same_name;
  DBUG_ENTER("partition_info::check_partition_info");

  if (unlikely(!is_sub_partitioned() && 
               !(use_default_subpartitions && use_default_no_subpartitions)))
  {
    my_error(ER_SUBPARTITION_ERROR, MYF(0));
    goto end;
  }
  if (unlikely(is_sub_partitioned() &&
              (!(part_type == RANGE_PARTITION || 
                 part_type == LIST_PARTITION))))
  {
    /* Only RANGE and LIST partitioning can be subpartitioned */
    my_error(ER_SUBPARTITION_ERROR, MYF(0));
    goto end;
  }
  if (unlikely(set_up_defaults_for_partitioning(file, max_rows, (uint)0)))
    goto end;
  tot_partitions= get_tot_partitions();
  if (unlikely(tot_partitions > MAX_PARTITIONS))
  {
    my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
    goto end;
  }
  if ((same_name= has_unique_names()))
  {
    my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name);
    goto end;
  }
  engine_array= (handlerton**)my_malloc(tot_partitions * sizeof(handlerton *), 
                                        MYF(MY_WME));
  if (unlikely(!engine_array))
    goto end;
  i= 0;
  {
    List_iterator<partition_element> part_it(partitions);
    do
    {
      partition_element *part_elem= part_it++;
      if (!is_sub_partitioned())
      {
        if (part_elem->engine_type == NULL)
          part_elem->engine_type= default_engine_type;
        DBUG_PRINT("info", ("engine = %d",
                   ha_legacy_type(part_elem->engine_type)));
        engine_array[part_count++]= part_elem->engine_type;
      }
      else
      {
        uint j= 0;
        List_iterator<partition_element> sub_it(part_elem->subpartitions);
        do
        {
          part_elem= sub_it++;
          if (part_elem->engine_type == NULL)
            part_elem->engine_type= default_engine_type;
          DBUG_PRINT("info", ("engine = %u",
                     ha_legacy_type(part_elem->engine_type)));
          engine_array[part_count++]= part_elem->engine_type;
        } while (++j < no_subparts);
      }
    } while (++i < no_parts);
  }
  if (unlikely(partition_info::check_engine_mix(engine_array, part_count)))
  {
    my_error(ER_MIX_HANDLER_ERROR, MYF(0));
    goto end;
  }

  if (eng_type)
    *eng_type= (handlerton*)engine_array[0];

  /*
    We need to check all constant expressions that they are of the correct
    type and that they are increasing for ranges and not overlapping for
    list constants.
  */

  if (unlikely((part_type == RANGE_PARTITION && check_range_constants()) ||
                (part_type == LIST_PARTITION && check_list_constants())))
    goto end;
  result= FALSE;
end:
  my_free((char*)engine_array,MYF(MY_ALLOW_ZERO_PTR));
  DBUG_RETURN(result);
}


#endif /* WITH_PARTITION_STORAGE_ENGINE */
Loading