mirror of
https://github.com/MariaDB/server.git
synced 2025-01-21 06:22:28 +01:00
8074262eda
added THD::work_part_info member where we now store modified partition_info structure. It allows no solve problem when different parts of the part_info get into different mem_roots
391 lines
11 KiB
C++
391 lines
11 KiB
C++
/* Copyright (C) 2006 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 */
|
|
|
|
/* Some general useful functions */
|
|
|
|
#ifdef USE_PRAGMA_IMPLEMENTATION
|
|
#pragma implementation
|
|
#endif
|
|
|
|
#include "mysql_priv.h"
|
|
#include "ha_partition.h"
|
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
|
|
partition_info *partition_info::get_clone()
|
|
{
|
|
if (!this)
|
|
return 0;
|
|
List_iterator<partition_element> part_it(partitions);
|
|
partition_element *part;
|
|
partition_info *clone= new partition_info();
|
|
if (!clone)
|
|
{
|
|
mem_alloc_error(sizeof(partition_info));
|
|
return NULL;
|
|
}
|
|
memcpy(clone, this, sizeof(partition_info));
|
|
clone->partitions.empty();
|
|
|
|
while ((part= (part_it++)))
|
|
{
|
|
List_iterator<partition_element> subpart_it(part->subpartitions);
|
|
partition_element *subpart;
|
|
partition_element *part_clone= new partition_element();
|
|
if (!part_clone)
|
|
{
|
|
mem_alloc_error(sizeof(partition_element));
|
|
return NULL;
|
|
}
|
|
memcpy(part_clone, part, sizeof(partition_element));
|
|
part_clone->subpartitions.empty();
|
|
while ((subpart= (subpart_it++)))
|
|
{
|
|
partition_element *subpart_clone= new partition_element();
|
|
if (!subpart_clone)
|
|
{
|
|
mem_alloc_error(sizeof(partition_element));
|
|
return NULL;
|
|
}
|
|
memcpy(subpart_clone, subpart, sizeof(partition_element));
|
|
part_clone->subpartitions.push_back(subpart_clone);
|
|
}
|
|
clone->partitions.push_back(part_clone);
|
|
}
|
|
return clone;
|
|
}
|
|
|
|
/*
|
|
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)
|
|
{
|
|
uint i, j;
|
|
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);
|
|
}
|
|
|
|
|
|
/*
|
|
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
|
|
*/
|
|
|
|
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())
|
|
{
|
|
partition_element *sub_el;
|
|
List_iterator<partition_element> subparts_it(el->subpartitions);
|
|
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())
|
|
{
|
|
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 */
|