2006-02-16 17:38:33 +01:00
|
|
|
/* Copyright (C) 2005 MySQL AB
|
|
|
|
|
|
|
|
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; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
|
|
|
|
/*
|
|
|
|
This file was introduced as a container for general functionality related
|
|
|
|
to partitioning introduced in MySQL version 5.1. It contains functionality
|
|
|
|
used by all handlers that support partitioning, which in the first version
|
|
|
|
is the partitioning handler itself and the NDB handler.
|
|
|
|
|
|
|
|
The first version was written by Mikael Ronstrom.
|
|
|
|
|
|
|
|
This version supports RANGE partitioning, LIST partitioning, HASH
|
|
|
|
partitioning and composite partitioning (hereafter called subpartitioning)
|
|
|
|
where each RANGE/LIST partitioning is HASH partitioned. The hash function
|
|
|
|
can either be supplied by the user or by only a list of fields (also
|
|
|
|
called KEY partitioning, where the MySQL server will use an internal
|
|
|
|
hash function.
|
|
|
|
There are quite a few defaults that can be used as well.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Some general useful functions */
|
|
|
|
|
|
|
|
#include "mysql_priv.h"
|
|
|
|
#include "ha_partition.h"
|
|
|
|
|
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Create a memory area where default partition names are stored and fill it
|
|
|
|
up with the names.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
create_default_partition_names()
|
|
|
|
part_no Partition number for subparts
|
|
|
|
no_parts Number of partitions
|
|
|
|
start_no Starting partition number
|
|
|
|
subpart Is it subpartitions
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
A pointer to the memory area of the default partition names
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
A support routine for the partition code where default values are
|
|
|
|
generated.
|
|
|
|
The external routine needing this code is check_partition_info
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define MAX_PART_NAME_SIZE 16
|
|
|
|
|
|
|
|
char *partition_info::create_default_partition_names(uint part_no, uint no_parts,
|
|
|
|
uint start_no, bool is_subpart)
|
|
|
|
{
|
|
|
|
char *ptr= sql_calloc(no_parts*MAX_PART_NAME_SIZE);
|
|
|
|
char *move_ptr= ptr;
|
|
|
|
uint i= 0;
|
|
|
|
DBUG_ENTER("create_default_partition_names");
|
|
|
|
|
|
|
|
if (likely(ptr != 0))
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (is_subpart)
|
|
|
|
my_sprintf(move_ptr, (move_ptr,"p%usp%u", part_no, (start_no + i)));
|
|
|
|
else
|
|
|
|
my_sprintf(move_ptr, (move_ptr,"p%u", (start_no + i)));
|
|
|
|
move_ptr+=MAX_PART_NAME_SIZE;
|
|
|
|
} while (++i < no_parts);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mem_alloc_error(no_parts*MAX_PART_NAME_SIZE);
|
|
|
|
}
|
|
|
|
DBUG_RETURN(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Set up all the default partitions not set-up by the user in the SQL
|
|
|
|
statement. Also perform a number of checks that the user hasn't tried
|
|
|
|
to use default values where no defaults exists.
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
TRUE Error, attempted default values not possible
|
|
|
|
FALSE Ok, default partitions set-up
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
The routine uses the underlying handler of the partitioning to define
|
|
|
|
the default number of partitions. For some handlers this requires
|
|
|
|
knowledge of the maximum number of rows to be stored in the table.
|
|
|
|
This routine only accepts HASH and KEY partitioning and thus there is
|
|
|
|
no subpartitioning if this routine is successful.
|
|
|
|
The external routine needing this code is check_partition_info
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool partition_info::set_up_default_partitions(handler *file, ulonglong max_rows,
|
|
|
|
uint start_no)
|
|
|
|
{
|
|
|
|
uint i;
|
|
|
|
char *default_name;
|
|
|
|
bool result= TRUE;
|
|
|
|
DBUG_ENTER("partition_info::set_up_default_partitions");
|
|
|
|
|
|
|
|
if (part_type != HASH_PARTITION)
|
|
|
|
{
|
|
|
|
const char *error_string;
|
|
|
|
if (part_type == RANGE_PARTITION)
|
|
|
|
error_string= partition_keywords[PKW_RANGE].str;
|
|
|
|
else
|
|
|
|
error_string= partition_keywords[PKW_LIST].str;
|
|
|
|
my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_string);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
if (no_parts == 0)
|
|
|
|
no_parts= file->get_default_no_partitions(max_rows);
|
|
|
|
if (unlikely(no_parts > MAX_PARTITIONS))
|
|
|
|
{
|
|
|
|
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
if (unlikely((!(default_name= create_default_partition_names(0, no_parts,
|
|
|
|
start_no,
|
|
|
|
FALSE)))))
|
|
|
|
goto end;
|
|
|
|
i= 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
partition_element *part_elem= new partition_element();
|
|
|
|
if (likely(part_elem != 0 &&
|
|
|
|
(!partitions.push_back(part_elem))))
|
|
|
|
{
|
|
|
|
part_elem->engine_type= default_engine_type;
|
|
|
|
part_elem->partition_name= default_name;
|
|
|
|
default_name+=MAX_PART_NAME_SIZE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mem_alloc_error(sizeof(partition_element));
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
} while (++i < no_parts);
|
|
|
|
result= FALSE;
|
|
|
|
end:
|
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Set up all the default subpartitions not set-up by the user in the SQL
|
|
|
|
statement. Also perform a number of checks that the default partitioning
|
|
|
|
becomes an allowed partitioning scheme.
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
TRUE Error, attempted default values not possible
|
|
|
|
FALSE Ok, default partitions set-up
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
The routine uses the underlying handler of the partitioning to define
|
|
|
|
the default number of partitions. For some handlers this requires
|
|
|
|
knowledge of the maximum number of rows to be stored in the table.
|
|
|
|
This routine is only called for RANGE or LIST partitioning and those
|
|
|
|
need to be specified so only subpartitions are specified.
|
|
|
|
The external routine needing this code is check_partition_info
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool partition_info::set_up_default_subpartitions(handler *file,
|
|
|
|
ulonglong max_rows)
|
|
|
|
{
|
2006-02-16 19:01:14 +01:00
|
|
|
uint i, j;
|
2006-02-16 17:38:33 +01:00
|
|
|
char *default_name, *name_ptr;
|
|
|
|
bool result= TRUE;
|
|
|
|
partition_element *part_elem;
|
|
|
|
List_iterator<partition_element> part_it(partitions);
|
|
|
|
DBUG_ENTER("partition_info::set_up_default_subpartitions");
|
|
|
|
|
|
|
|
if (no_subparts == 0)
|
|
|
|
no_subparts= file->get_default_no_partitions(max_rows);
|
|
|
|
if (unlikely((no_parts * no_subparts) > MAX_PARTITIONS))
|
|
|
|
{
|
|
|
|
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
i= 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
part_elem= part_it++;
|
|
|
|
j= 0;
|
|
|
|
name_ptr= create_default_partition_names(i, no_subparts, (uint)0, TRUE);
|
|
|
|
if (unlikely(!name_ptr))
|
|
|
|
goto end;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
partition_element *subpart_elem= new partition_element();
|
|
|
|
if (likely(subpart_elem != 0 &&
|
|
|
|
(!part_elem->subpartitions.push_back(subpart_elem))))
|
|
|
|
{
|
|
|
|
subpart_elem->engine_type= default_engine_type;
|
|
|
|
subpart_elem->partition_name= name_ptr;
|
|
|
|
name_ptr+= MAX_PART_NAME_SIZE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mem_alloc_error(sizeof(partition_element));
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
} while (++j < no_subparts);
|
|
|
|
} while (++i < no_parts);
|
|
|
|
result= FALSE;
|
|
|
|
end:
|
|
|
|
DBUG_RETURN(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Support routine for check_partition_info
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
TRUE Error, attempted default values not possible
|
|
|
|
FALSE Ok, default partitions set-up
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Set up defaults for partition or subpartition (cannot set-up for both,
|
|
|
|
this will return an error.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool partition_info::set_up_defaults_for_partitioning(handler *file,
|
|
|
|
ulonglong max_rows,
|
|
|
|
uint start_no)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("partition_info::set_up_defaults_for_partitioning");
|
|
|
|
|
|
|
|
if (!default_partitions_setup)
|
|
|
|
{
|
|
|
|
default_partitions_setup= TRUE;
|
|
|
|
if (use_default_partitions)
|
|
|
|
DBUG_RETURN(set_up_default_partitions(file, max_rows, start_no));
|
|
|
|
if (is_sub_partitioned() &&
|
|
|
|
use_default_subpartitions)
|
|
|
|
DBUG_RETURN(set_up_default_subpartitions(file, max_rows));
|
|
|
|
}
|
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
}
|
|
|
|
|
2006-02-16 19:01:14 +01:00
|
|
|
/*
|
|
|
|
A support function to check if a partition element's name is unique
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
has_unique_name()
|
|
|
|
partition_element element to check
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
TRUE Has unique name
|
|
|
|
FALSE Doesn't
|
|
|
|
*/
|
2006-02-16 17:38:33 +01:00
|
|
|
bool partition_info::has_unique_name(partition_element *element)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("partition_info::has_unique_name");
|
|
|
|
|
|
|
|
const char *name_to_check= element->partition_name;
|
|
|
|
List_iterator<partition_element> parts_it(partitions);
|
|
|
|
|
|
|
|
partition_element *el;
|
|
|
|
while (el= (parts_it++))
|
|
|
|
{
|
|
|
|
if (!(my_strcasecmp(system_charset_info, el->partition_name,
|
|
|
|
name_to_check)) && el != element)
|
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
|
|
|
|
if (el->subpartitions.is_empty()) continue;
|
|
|
|
List_iterator<partition_element> subparts_it(el->subpartitions);
|
|
|
|
partition_element *sub_el;
|
|
|
|
while (sub_el= (subparts_it++))
|
|
|
|
{
|
|
|
|
if (!(my_strcasecmp(system_charset_info, sub_el->partition_name,
|
|
|
|
name_to_check)) && sub_el != element)
|
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
A support function to check partition names for duplication in a
|
|
|
|
partitioned table
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
has_unique_names()
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
TRUE Has unique part and subpart names
|
|
|
|
FALSE Doesn't
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
Checks that the list of names in the partitions doesn't contain any
|
|
|
|
duplicated names.
|
|
|
|
*/
|
|
|
|
char *partition_info::has_unique_names()
|
|
|
|
{
|
|
|
|
DBUG_ENTER("partition_info::has_unique_names");
|
|
|
|
|
|
|
|
List_iterator<partition_element> parts_it(partitions);
|
|
|
|
|
|
|
|
partition_element *el;
|
|
|
|
while (el= (parts_it++))
|
|
|
|
{
|
|
|
|
if (! has_unique_name(el))
|
|
|
|
DBUG_RETURN(el->partition_name);
|
|
|
|
|
|
|
|
if (el->subpartitions.is_empty()) continue;
|
|
|
|
List_iterator<partition_element> subparts_it(el->subpartitions);
|
|
|
|
partition_element *subel;
|
|
|
|
while (subel= (subparts_it++))
|
|
|
|
{
|
|
|
|
if (! has_unique_name(subel))
|
|
|
|
DBUG_RETURN(subel->partition_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DBUG_RETURN(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* WITH_PARTITION_STORAGE_ENGINE */
|