ha_partition.cc and ha_partition.h are now completely merged

Added sql_mode_t to simplify merges
This commit is contained in:
Michael Widenius 2013-06-27 14:01:03 +03:00
parent e7606294b2
commit 94d722b6a4
12 changed files with 569 additions and 240 deletions

View File

@ -280,7 +280,9 @@ static void free_memory(void *ptr)
static void warn(const char *format,...) static void warn(const char *format,...)
{ {
va_list args; va_list args;
DBUG_PRINT("error", ("%s", format));
va_start(args,format); va_start(args,format);
fflush(stderr);
vfprintf(stderr, format, args); vfprintf(stderr, format, args);
va_end(args); va_end(args);

View File

@ -1,5 +1,6 @@
/* /*
Copyright (c) 2005, 2012, Oracle and/or its affiliates. Copyright (c) 2005, 2012, Oracle and/or its affiliates.
Copyright (c) 2009-2013 Monty Program Ab & SkySQL Ab
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -36,7 +37,7 @@
in the execution of queries. This functionality will grow with later in the execution of queries. This functionality will grow with later
versions of MySQL. versions of MySQL.
You can enable it in your buld by doing the following during your build You can enable it in your build by doing the following during your build
process: process:
./configure --with-partition ./configure --with-partition
@ -49,10 +50,6 @@
if this file. if this file.
*/ */
#ifdef __GNUC__
#pragma implementation // gcc: Class implementation
#endif
#include "sql_priv.h" #include "sql_priv.h"
#include "sql_parse.h" // append_file_to_dir #include "sql_parse.h" // append_file_to_dir
#include "create_options.h" #include "create_options.h"
@ -64,6 +61,20 @@
#include "sql_plugin.h" #include "sql_plugin.h"
#include "debug_sync.h" #include "debug_sync.h"
/* First 4 bytes in the .par file is the number of 32-bit words in the file */
#define PAR_WORD_SIZE 4
/* offset to the .par file checksum */
#define PAR_CHECKSUM_OFFSET 4
/* offset to the total number of partitions */
#define PAR_NUM_PARTS_OFFSET 8
/* offset to the engines array */
#define PAR_ENGINES_OFFSET 12
#define PARTITION_ENABLED_TABLE_FLAGS (HA_FILE_BASED | HA_REC_NOT_IN_SEQ)
#define PARTITION_DISABLED_TABLE_FLAGS (HA_CAN_GEOMETRY | \
HA_CAN_FULLTEXT | \
HA_DUPLICATE_POS | \
HA_CAN_SQL_HANDLER | \
HA_CAN_INSERT_DELAYED)
static const char *ha_par_ext= ".par"; static const char *ha_par_ext= ".par";
/**************************************************************************** /****************************************************************************
@ -306,7 +317,6 @@ void ha_partition::init_handler_variables()
m_added_file= NULL; m_added_file= NULL;
m_tot_parts= 0; m_tot_parts= 0;
m_pkey_is_clustered= 0; m_pkey_is_clustered= 0;
m_lock_type= F_UNLCK;
m_part_spec.start_part= NO_CURRENT_PART_ID; m_part_spec.start_part= NO_CURRENT_PART_ID;
m_scan_value= 2; m_scan_value= 2;
m_ref_length= 0; m_ref_length= 0;
@ -352,6 +362,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 Destructor method
@ -1348,6 +1365,8 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt,
@retval TRUE Error/Not supported @retval TRUE Error/Not supported
@retval FALSE Success @retval FALSE Success
@note Called if open_table_from_share fails and ::is_crashed().
*/ */
bool ha_partition::check_and_repair(THD *thd) bool ha_partition::check_and_repair(THD *thd)
@ -1427,6 +1446,22 @@ int ha_partition::prepare_new_partition(TABLE *tbl,
int error; int error;
DBUG_ENTER("prepare_new_partition"); DBUG_ENTER("prepare_new_partition");
/*
This call to set_up_table_before_create() is done for an alter table.
So this may be the second time around for this partition_element,
depending on how many partitions and subpartitions there were before,
and how many there are now.
The first time, on the CREATE, data_file_name and index_file_name
came from the parser. They did not have the file name attached to
the end. But if this partition is less than the total number of
previous partitions, it's data_file_name has the filename attached.
So we need to take the partition filename off if it exists.
That file name may be different from part_name, which will be
attached in append_file_to_dir().
*/
truncate_partition_filename(p_elem->data_file_name);
truncate_partition_filename(p_elem->index_file_name);
if ((error= set_up_table_before_create(tbl, part_name, create_info, p_elem))) if ((error= set_up_table_before_create(tbl, part_name, create_info, p_elem)))
goto error_create; goto error_create;
@ -1721,7 +1756,8 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
DBUG_RETURN(HA_ERR_OUT_OF_MEM); DBUG_RETURN(HA_ERR_OUT_OF_MEM);
if (m_new_partitions_share_refs.push_back(p_share_refs)) if (m_new_partitions_share_refs.push_back(p_share_refs))
DBUG_RETURN(HA_ERR_OUT_OF_MEM); DBUG_RETURN(HA_ERR_OUT_OF_MEM);
{ do
{
handler **new_file= &new_file_array[part_count++]; handler **new_file= &new_file_array[part_count++];
if (!(*new_file= if (!(*new_file=
get_new_handler(table->s, get_new_handler(table->s,
@ -1889,7 +1925,7 @@ int ha_partition::copy_partitions(ulonglong * const copied,
late_extra_cache(reorg_part); late_extra_cache(reorg_part);
if ((result= file->ha_rnd_init_with_error(1))) if ((result= file->ha_rnd_init_with_error(1)))
goto error; goto init_error;
while (TRUE) while (TRUE)
{ {
if ((result= file->ha_rnd_next(m_rec0))) if ((result= file->ha_rnd_next(m_rec0)))
@ -1934,6 +1970,7 @@ int ha_partition::copy_partitions(ulonglong * const copied,
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
error: error:
m_reorged_file[reorg_part]->ha_rnd_end(); m_reorged_file[reorg_part]->ha_rnd_end();
init_error:
DBUG_RETURN(result); DBUG_RETURN(result);
} }
@ -1949,11 +1986,16 @@ error:
NONE NONE
DESCRIPTION DESCRIPTION
Method empty so far Forward this handler call to the storage engine foreach
partition handler. The data_file_name for each partition may
need to be reset if the tablespace was moved. Use a dummy
HA_CREATE_INFO structure and transfer necessary data.
*/ */
void ha_partition::update_create_info(HA_CREATE_INFO *create_info) void ha_partition::update_create_info(HA_CREATE_INFO *create_info)
{ {
DBUG_ENTER("ha_partition::update_create_info");
/* /*
Fix for bug#38751, some engines needs info-calls in ALTER. Fix for bug#38751, some engines needs info-calls in ALTER.
Archive need this since it flushes in ::info. Archive need this since it flushes in ::info.
@ -1967,10 +2009,117 @@ void ha_partition::update_create_info(HA_CREATE_INFO *create_info)
if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
create_info->auto_increment_value= stats.auto_increment_value; create_info->auto_increment_value= stats.auto_increment_value;
/*
DATA DIRECTORY and INDEX DIRECTORY are never applied to the whole
partitioned table, only its parts.
*/
my_bool from_alter = (create_info->data_file_name == (const char*) -1);
create_info->data_file_name= create_info->index_file_name = NULL; create_info->data_file_name= create_info->index_file_name = NULL;
create_info->connect_string.str= NULL; create_info->connect_string.str= NULL;
create_info->connect_string.length= 0; create_info->connect_string.length= 0;
return;
/*
We do not need to update the individual partition DATA DIRECTORY settings
since they can be changed by ALTER TABLE ... REORGANIZE PARTITIONS.
*/
if (from_alter)
DBUG_VOID_RETURN;
/*
send Handler::update_create_info() to the storage engine for each
partition that currently has a handler object. Using a dummy
HA_CREATE_INFO structure to collect DATA and INDEX DIRECTORYs.
*/
List_iterator<partition_element> part_it(m_part_info->partitions);
partition_element *part_elem, *sub_elem;
uint num_subparts= m_part_info->num_subparts;
uint num_parts = num_subparts ? m_file_tot_parts / num_subparts
: m_file_tot_parts;
HA_CREATE_INFO dummy_info;
memset(&dummy_info, 0, sizeof(dummy_info));
/*
Since update_create_info() can be called from mysql_prepare_alter_table()
when not all handlers are set up, we look for that condition first.
If all handlers are not available, do not call update_create_info for any.
*/
uint i, j, part;
for (i= 0; i < num_parts; i++)
{
part_elem= part_it++;
if (!part_elem)
DBUG_VOID_RETURN;
if (m_is_sub_partitioned)
{
List_iterator<partition_element> subpart_it(part_elem->subpartitions);
for (j= 0; j < num_subparts; j++)
{
sub_elem= subpart_it++;
if (!sub_elem)
DBUG_VOID_RETURN;
part= i * num_subparts + j;
if (part >= m_file_tot_parts || !m_file[part])
DBUG_VOID_RETURN;
}
}
else
{
if (!m_file[i])
DBUG_VOID_RETURN;
}
}
part_it.rewind();
for (i= 0; i < num_parts; i++)
{
part_elem= part_it++;
DBUG_ASSERT(part_elem);
if (m_is_sub_partitioned)
{
List_iterator<partition_element> subpart_it(part_elem->subpartitions);
for (j= 0; j < num_subparts; j++)
{
sub_elem= subpart_it++;
DBUG_ASSERT(sub_elem);
part= i * num_subparts + j;
DBUG_ASSERT(part < m_file_tot_parts && m_file[part]);
if (ha_legacy_type(m_file[part]->ht) == DB_TYPE_INNODB)
{
dummy_info.data_file_name= dummy_info.index_file_name = NULL;
m_file[part]->update_create_info(&dummy_info);
if (dummy_info.data_file_name || sub_elem->data_file_name)
{
sub_elem->data_file_name = (char*) dummy_info.data_file_name;
}
if (dummy_info.index_file_name || sub_elem->index_file_name)
{
sub_elem->index_file_name = (char*) dummy_info.index_file_name;
}
}
}
}
else
{
DBUG_ASSERT(m_file[i]);
if (ha_legacy_type(m_file[i]->ht) == DB_TYPE_INNODB)
{
dummy_info.data_file_name= dummy_info.index_file_name= NULL;
m_file[i]->update_create_info(&dummy_info);
if (dummy_info.data_file_name || part_elem->data_file_name)
{
part_elem->data_file_name = (char*) dummy_info.data_file_name;
}
if (dummy_info.index_file_name || part_elem->index_file_name)
{
part_elem->index_file_name = (char*) dummy_info.index_file_name;
}
}
}
}
DBUG_VOID_RETURN;
} }
@ -2034,7 +2183,6 @@ char *ha_partition::update_table_comment(const char *comment)
} }
/** /**
Handle delete and rename table Handle delete and rename table
@ -2098,14 +2246,14 @@ uint ha_partition::del_ren_table(const char *from, const char *to)
NORMAL_PART_NAME, FALSE); NORMAL_PART_NAME, FALSE);
if (to != NULL) if (to != NULL)
{ // Rename branch { // Rename branch
create_partition_name(to_buff, to_path, name_buffer_ptr, create_partition_name(to_buff, to_path, name_buffer_ptr,
NORMAL_PART_NAME, FALSE); NORMAL_PART_NAME, FALSE);
error= (*file)->ha_rename_table(from_buff, to_buff); error= (*file)->ha_rename_table(from_buff, to_buff);
if (error) if (error)
goto rename_error; goto rename_error;
} }
else // delete branch else // delete branch
{ {
error= (*file)->ha_delete_table(from_buff); error= (*file)->ha_delete_table(from_buff);
} }
@ -2435,10 +2583,8 @@ bool ha_partition::create_handler_file(const char *name)
/* 4 static words (tot words, checksum, tot partitions, name length) */ /* 4 static words (tot words, checksum, tot partitions, name length) */
tot_len_words= 4 + tot_partition_words + tot_name_words; tot_len_words= 4 + tot_partition_words + tot_name_words;
tot_len_byte= PAR_WORD_SIZE * tot_len_words; tot_len_byte= PAR_WORD_SIZE * tot_len_words;
file_buffer= (uchar *) my_alloca(tot_len_byte); if (!(file_buffer= (uchar *) my_malloc(tot_len_byte, MYF(MY_ZEROFILL))))
if (!file_buffer)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
bzero(file_buffer, tot_len_byte);
engine_array= (file_buffer + PAR_ENGINES_OFFSET); engine_array= (file_buffer + PAR_ENGINES_OFFSET);
name_buffer_ptr= (char*) (engine_array + tot_partition_words * PAR_WORD_SIZE name_buffer_ptr= (char*) (engine_array + tot_partition_words * PAR_WORD_SIZE
+ PAR_WORD_SIZE); + PAR_WORD_SIZE);
@ -2519,7 +2665,7 @@ bool ha_partition::create_handler_file(const char *name)
} }
else else
result= TRUE; result= TRUE;
my_afree((char*) file_buffer); my_free(file_buffer);
DBUG_RETURN(result); DBUG_RETURN(result);
} }
@ -2531,16 +2677,11 @@ bool ha_partition::create_handler_file(const char *name)
void ha_partition::clear_handler_file() void ha_partition::clear_handler_file()
{ {
if (m_engine_array) if (m_engine_array)
{
plugin_unlock_list(NULL, m_engine_array, m_tot_parts); plugin_unlock_list(NULL, m_engine_array, m_tot_parts);
my_free(m_engine_array); free_root(&m_mem_root, MYF(MY_KEEP_PREALLOC));
m_engine_array= NULL; m_file_buffer= NULL;
} m_engine_array= NULL;
if (m_file_buffer) m_connect_string= NULL;
{
my_free(m_file_buffer);
m_file_buffer= NULL;
}
} }
@ -2675,9 +2816,10 @@ error_end:
bool ha_partition::read_par_file(const char *name) bool ha_partition::read_par_file(const char *name)
{ {
char buff[FN_REFLEN], *tot_name_len_offset; char buff[FN_REFLEN];
uchar *tot_name_len_offset;
File file; File file;
char *file_buffer; uchar *file_buffer;
uint i, len_bytes, len_words, tot_partition_words, tot_name_words, chksum; uint i, len_bytes, len_words, tot_partition_words, tot_name_words, chksum;
DBUG_ENTER("ha_partition::read_par_file"); DBUG_ENTER("ha_partition::read_par_file");
DBUG_PRINT("enter", ("table name: '%s'", name)); DBUG_PRINT("enter", ("table name: '%s'", name));
@ -2696,9 +2838,9 @@ bool ha_partition::read_par_file(const char *name)
len_bytes= PAR_WORD_SIZE * len_words; len_bytes= PAR_WORD_SIZE * len_words;
if (mysql_file_seek(file, 0, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR) if (mysql_file_seek(file, 0, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR)
goto err1; goto err1;
if (!(file_buffer= (char*) alloc_root(&m_mem_root, len_bytes))) if (!(file_buffer= (uchar*) alloc_root(&m_mem_root, len_bytes)))
goto err1; goto err1;
if (mysql_file_read(file, (uchar *) file_buffer, len_bytes, MYF(MY_NABP))) if (mysql_file_read(file, file_buffer, len_bytes, MYF(MY_NABP)))
goto err2; goto err2;
chksum= 0; chksum= 0;
@ -2721,7 +2863,7 @@ bool ha_partition::read_par_file(const char *name)
if (len_words != (tot_partition_words + tot_name_words + 4)) if (len_words != (tot_partition_words + tot_name_words + 4))
goto err2; goto err2;
m_file_buffer= file_buffer; // Will be freed in clear_handler_file() m_file_buffer= file_buffer; // Will be freed in clear_handler_file()
m_name_buffer_ptr= tot_name_len_offset + PAR_WORD_SIZE; m_name_buffer_ptr= (char*) (tot_name_len_offset + PAR_WORD_SIZE);
if (!(m_connect_string= (LEX_STRING*) if (!(m_connect_string= (LEX_STRING*)
alloc_root(&m_mem_root, m_tot_parts * sizeof(LEX_STRING)))) alloc_root(&m_mem_root, m_tot_parts * sizeof(LEX_STRING))))
@ -2771,7 +2913,8 @@ bool ha_partition::setup_engine_array(MEM_ROOT *mem_root)
{ {
uint i; uint i;
uchar *buff; uchar *buff;
handlerton **engine_array; handlerton **engine_array, *first_engine;
enum legacy_db_type db_type, first_db_type;
DBUG_ASSERT(!m_file); DBUG_ASSERT(!m_file);
DBUG_ENTER("ha_partition::setup_engine_array"); DBUG_ENTER("ha_partition::setup_engine_array");
@ -2780,22 +2923,36 @@ bool ha_partition::setup_engine_array(MEM_ROOT *mem_root)
DBUG_RETURN(true); DBUG_RETURN(true);
buff= (uchar *) (m_file_buffer + PAR_ENGINES_OFFSET); buff= (uchar *) (m_file_buffer + PAR_ENGINES_OFFSET);
for (i= 0; i < m_tot_parts; i++) first_db_type= (enum legacy_db_type) buff[0];
{ first_engine= ha_resolve_by_legacy_type(ha_thd(), first_db_type);
engine_array[i]= ha_resolve_by_legacy_type(ha_thd(), if (!first_engine)
(enum legacy_db_type) goto err;
*(buff + i));
if (!engine_array[i])
goto err;
}
if (!(m_engine_array= (plugin_ref*) if (!(m_engine_array= (plugin_ref*)
alloc_root(&m_mem_root, m_tot_parts * sizeof(plugin_ref)))) alloc_root(&m_mem_root, m_tot_parts * sizeof(plugin_ref))))
goto err; goto err;
for (i= 0; i < m_tot_parts; i++) for (i= 0; i < m_tot_parts; i++)
m_engine_array[i]= ha_lock_engine(NULL, engine_array[i]); {
db_type= (enum legacy_db_type) buff[i];
if (db_type != first_db_type)
{
DBUG_PRINT("error", ("partition %u engine %d is not same as "
"first partition %d", i, db_type,
(int) first_db_type));
DBUG_ASSERT(0);
clear_handler_file();
goto err;
}
m_engine_array[i]= ha_lock_engine(NULL, first_engine);
if (!m_engine_array[i])
{
clear_handler_file();
goto err;
}
}
my_afree(engine_array); my_afree((gptr) engine_array);
if (create_handlers(mem_root)) if (create_handlers(mem_root))
{ {
@ -2806,7 +2963,7 @@ bool ha_partition::setup_engine_array(MEM_ROOT *mem_root)
DBUG_RETURN(false); DBUG_RETURN(false);
err: err:
my_afree(engine_array); my_afree((gptr) engine_array);
DBUG_RETURN(true); DBUG_RETURN(true);
} }
@ -2849,7 +3006,6 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root,
MODULE open/close object MODULE open/close object
****************************************************************************/ ****************************************************************************/
/** /**
Get the partition name. Get the partition name.
@ -3270,7 +3426,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
(PARTITION_ENABLED_TABLE_FLAGS))) (PARTITION_ENABLED_TABLE_FLAGS)))
{ {
error= HA_ERR_INITIALIZATION; error= HA_ERR_INITIALIZATION;
/* set file to last handler, so all of them is closed */ /* set file to last handler, so all of them are closed */
file = &m_file[m_tot_parts - 1]; file = &m_file[m_tot_parts - 1];
goto err_handler; goto err_handler;
} }
@ -3316,6 +3472,13 @@ err_alloc:
} }
/*
Disabled since it is not possible to prune yet.
without pruning, it need to rebind/unbind every partition in every
statement which uses a table from the table cache. Will also use
as many PSI_tables as there are partitions.
*/
#ifdef HAVE_M_PSI_PER_PARTITION
void ha_partition::unbind_psi() void ha_partition::unbind_psi()
{ {
uint i; uint i;
@ -3343,6 +3506,7 @@ void ha_partition::rebind_psi()
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
#endif /* HAVE_M_PSI_PER_PARTITION */
/** /**
@ -3839,7 +4003,7 @@ int ha_partition::write_row(uchar * buf)
bool have_auto_increment= table->next_number_field && buf == table->record[0]; bool have_auto_increment= table->next_number_field && buf == table->record[0];
my_bitmap_map *old_map; my_bitmap_map *old_map;
THD *thd= ha_thd(); THD *thd= ha_thd();
ulonglong saved_sql_mode= thd->variables.sql_mode; sql_mode_t saved_sql_mode= thd->variables.sql_mode;
bool saved_auto_inc_field_not_null= table->auto_increment_field_not_null; bool saved_auto_inc_field_not_null= table->auto_increment_field_not_null;
DBUG_ENTER("ha_partition::write_row"); DBUG_ENTER("ha_partition::write_row");
DBUG_ASSERT(buf == m_rec0); DBUG_ASSERT(buf == m_rec0);
@ -3894,6 +4058,13 @@ int ha_partition::write_row(uchar * buf)
m_part_info->err_value= func_value; m_part_info->err_value= func_value;
goto exit; goto exit;
} }
if (!bitmap_is_set(&(m_part_info->lock_partitions), part_id))
{
DBUG_PRINT("info", ("Write to non-locked partition %u (func_value: %ld)",
part_id, (long) func_value));
error= HA_ERR_NOT_IN_LOCK_PARTITIONS;
goto exit;
}
m_last_part= part_id; m_last_part= part_id;
DBUG_PRINT("info", ("Insert in partition %d", part_id)); DBUG_PRINT("info", ("Insert in partition %d", part_id));
start_part_bulk_insert(thd, part_id); start_part_bulk_insert(thd, part_id);
@ -3942,6 +4113,9 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data)
longlong func_value; longlong func_value;
DBUG_ENTER("ha_partition::update_row"); DBUG_ENTER("ha_partition::update_row");
// Need to read partition-related columns, to locate the row's partition:
DBUG_ASSERT(bitmap_is_subset(&m_part_info->full_part_field_set,
table->read_set));
if ((error= get_parts_for_update(old_data, new_data, table->record[0], if ((error= get_parts_for_update(old_data, new_data, table->record[0],
m_part_info, &old_part_id, &new_part_id, m_part_info, &old_part_id, &new_part_id,
&func_value))) &func_value)))
@ -3949,7 +4123,12 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data)
m_part_info->err_value= func_value; m_part_info->err_value= func_value;
goto exit; goto exit;
} }
DBUG_ASSERT(bitmap_is_set(&(m_part_info->read_partitions), old_part_id));
if (!bitmap_is_set(&(m_part_info->lock_partitions), new_part_id))
{
error= HA_ERR_NOT_IN_LOCK_PARTITIONS;
goto exit;
}
m_last_part= new_part_id; m_last_part= new_part_id;
start_part_bulk_insert(thd, new_part_id); start_part_bulk_insert(thd, new_part_id);
if (new_part_id == old_part_id) if (new_part_id == old_part_id)
@ -4098,15 +4277,17 @@ int ha_partition::delete_row(const uchar *buf)
int ha_partition::delete_all_rows() int ha_partition::delete_all_rows()
{ {
int error; int error;
handler **file; uint i;
DBUG_ENTER("ha_partition::delete_all_rows"); DBUG_ENTER("ha_partition::delete_all_rows");
file= m_file; for (i= bitmap_get_first_set(&m_part_info->read_partitions);
do i < m_tot_parts;
i= bitmap_get_next_set(&m_part_info->read_partitions, i))
{ {
if ((error= (*file)->ha_delete_all_rows())) /* Can be pruned, like DELETE FROM t PARTITION (pX) */
if ((error= m_file[i]->ha_delete_all_rows()))
DBUG_RETURN(error); DBUG_RETURN(error);
} while (*(++file)); }
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@ -4130,8 +4311,8 @@ int ha_partition::truncate()
*/ */
lock_auto_increment(); lock_auto_increment();
part_share->next_auto_inc_val= 0; part_share->next_auto_inc_val= 0;
part_share->auto_inc_initialized= FALSE; part_share->auto_inc_initialized= false;
unlock_auto_increment(); unlock_auto_increment();
file= m_file; file= m_file;
do do
@ -4217,7 +4398,7 @@ int ha_partition::truncate_partition(Alter_info *alter_info, bool *binlog_stmt)
SYNOPSIS SYNOPSIS
start_bulk_insert() start_bulk_insert()
rows Number of rows to insert rows Number of rows to insert
flags Flags to control index creation flags Flags to control index creation
RETURN VALUE RETURN VALUE
NONE NONE
@ -4355,11 +4536,12 @@ int ha_partition::end_bulk_insert()
if (!bitmap_is_set(&m_bulk_insert_started, m_tot_parts)) if (!bitmap_is_set(&m_bulk_insert_started, m_tot_parts))
DBUG_RETURN(error); DBUG_RETURN(error);
for (i= 0; i < m_tot_parts; i++) for (i= bitmap_get_first_set(&m_bulk_insert_started);
i < m_tot_parts;
i= bitmap_get_next_set(&m_bulk_insert_started, i))
{ {
int tmp; int tmp;
if (bitmap_is_set(&m_bulk_insert_started, i) && if ((tmp= m_file[i]->ha_end_bulk_insert()))
(tmp= m_file[i]->ha_end_bulk_insert()))
error= tmp; error= tmp;
} }
bitmap_clear_all(&m_bulk_insert_started); bitmap_clear_all(&m_bulk_insert_started);
@ -4407,7 +4589,7 @@ int ha_partition::rnd_init(bool scan)
For operations that may need to change data, we may need to extend For operations that may need to change data, we may need to extend
read_set. read_set.
*/ */
if (m_lock_type == F_WRLCK) if (get_lock_type() == F_WRLCK)
{ {
/* /*
If write_set contains any of the fields used in partition and If write_set contains any of the fields used in partition and
@ -4584,7 +4766,7 @@ int ha_partition::rnd_next(uchar *buf)
} }
/* /*
if we get here, then the current partition rnd_next returned failure if we get here, then the current partition ha_rnd_next returned failure
*/ */
if (result == HA_ERR_RECORD_DELETED) if (result == HA_ERR_RECORD_DELETED)
continue; // Probably MyISAM continue; // Probably MyISAM
@ -4665,14 +4847,6 @@ void ha_partition::position(const uchar *record)
} }
void ha_partition::column_bitmaps_signal()
{
handler::column_bitmaps_signal();
/* Must read all partition fields to make position() call possible */
bitmap_union(table->read_set, &m_part_info->full_part_field_set);
}
/* /*
Read row using position Read row using position
@ -4775,7 +4949,7 @@ bool ha_partition::init_record_priority_queue()
{ {
uint alloc_len; uint alloc_len;
uint used_parts= bitmap_bits_set(&m_part_info->read_partitions); uint used_parts= bitmap_bits_set(&m_part_info->read_partitions);
/* Allocate record buffer for each used partition. */ /* Allocate record buffer for each used partition. */
alloc_len= used_parts * (m_rec_length + PARTITION_BYTES_IN_POS); alloc_len= used_parts * (m_rec_length + PARTITION_BYTES_IN_POS);
/* Allocate a key for temporary use when setting up the scan. */ /* Allocate a key for temporary use when setting up the scan. */
alloc_len+= table_share->max_key_length; alloc_len+= table_share->max_key_length;
@ -4884,7 +5058,7 @@ int ha_partition::index_init(uint inx, bool sorted)
calculate the partition id to place updated and deleted records. calculate the partition id to place updated and deleted records.
But this is required for operations that may need to change data only. But this is required for operations that may need to change data only.
*/ */
if (m_lock_type == F_WRLCK) if (get_lock_type() == F_WRLCK)
bitmap_union(table->read_set, &m_part_info->full_part_field_set); bitmap_union(table->read_set, &m_part_info->full_part_field_set);
if (sorted) if (sorted)
{ {
@ -5368,15 +5542,7 @@ int ha_partition::read_range_first(const key_range *start_key,
m_ordered= sorted; m_ordered= sorted;
eq_range= eq_range_arg; eq_range= eq_range_arg;
end_range= 0; set_end_range(end_key);
if (end_key)
{
end_range= &save_end_range;
save_end_range= *end_key;
key_compare_result_on_equal=
((end_key->flag == HA_READ_BEFORE_KEY) ? 1 :
(end_key->flag == HA_READ_AFTER_KEY) ? -1 : 0);
}
range_key_part= m_curr_key_info[0]->key_part; range_key_part= m_curr_key_info[0]->key_part;
if (start_key) if (start_key)
@ -5595,10 +5761,15 @@ int ha_partition::handle_unordered_next(uchar *buf, bool is_next_same)
int ha_partition::handle_unordered_scan_next_partition(uchar * buf) int ha_partition::handle_unordered_scan_next_partition(uchar * buf)
{ {
uint i; uint i= m_part_spec.start_part;
int saved_error= HA_ERR_END_OF_FILE; int saved_error= HA_ERR_END_OF_FILE;
DBUG_ENTER("ha_partition::handle_unordered_scan_next_partition"); DBUG_ENTER("ha_partition::handle_unordered_scan_next_partition");
if (i)
i= bitmap_get_next_set(&m_part_info->read_partitions, i - 1);
else
i= bitmap_get_first_set(&m_part_info->read_partitions);
for (; for (;
i <= m_part_spec.end_part; i <= m_part_spec.end_part;
i= bitmap_get_next_set(&m_part_info->read_partitions, i)) i= bitmap_get_next_set(&m_part_info->read_partitions, i))
@ -5720,7 +5891,9 @@ int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order)
} }
DBUG_PRINT("info", ("m_part_spec.start_part %u first_used_part %u", DBUG_PRINT("info", ("m_part_spec.start_part %u first_used_part %u",
m_part_spec.start_part, i)); m_part_spec.start_part, i));
for (i= m_part_spec.start_part; i <= m_part_spec.end_part; i++) for (/* continue from above */ ;
i <= m_part_spec.end_part;
i= bitmap_get_next_set(&m_part_info->read_partitions, i))
{ {
DBUG_PRINT("info", ("reading from part %u (scan_type: %u)", DBUG_PRINT("info", ("reading from part %u (scan_type: %u)",
i, m_index_scan_type)); i, m_index_scan_type));
@ -5848,7 +6021,7 @@ int ha_partition::handle_ordered_index_scan_key_not_found()
i < m_tot_parts; i < m_tot_parts;
i= bitmap_get_next_set(&m_part_info->read_partitions, i)) i= bitmap_get_next_set(&m_part_info->read_partitions, i))
{ {
if (bitmap_is_set(&m_key_not_found_partitions, i)) if (bitmap_is_set(&m_key_not_found_partitions, i))
{ {
/* /*
This partition is used and did return HA_ERR_KEY_NOT_FOUND This partition is used and did return HA_ERR_KEY_NOT_FOUND
@ -5864,7 +6037,6 @@ int ha_partition::handle_ordered_index_scan_key_not_found()
DBUG_RETURN(error); DBUG_RETURN(error);
} }
part_buf+= m_rec_length + PARTITION_BYTES_IN_POS; part_buf+= m_rec_length + PARTITION_BYTES_IN_POS;
part_buf+= m_rec_length + PARTITION_BYTES_IN_POS;
} }
DBUG_ASSERT(curr_rec_buf); DBUG_ASSERT(curr_rec_buf);
bitmap_clear_all(&m_key_not_found_partitions); bitmap_clear_all(&m_key_not_found_partitions);
@ -6122,7 +6294,7 @@ int ha_partition::info(uint flag)
if (!table->found_next_number_field) if (!table->found_next_number_field)
stats.auto_increment_value= 0; stats.auto_increment_value= 0;
else if (part_share->auto_inc_initialized) else if (part_share->auto_inc_initialized)
{ {
lock_auto_increment(); lock_auto_increment();
stats.auto_increment_value= part_share->next_auto_inc_val; stats.auto_increment_value= part_share->next_auto_inc_val;
unlock_auto_increment(); unlock_auto_increment();
@ -6135,7 +6307,7 @@ int ha_partition::info(uint flag)
stats.auto_increment_value= part_share->next_auto_inc_val; stats.auto_increment_value= part_share->next_auto_inc_val;
else else
{ {
/* /*
The auto-inc mutex in the table_share is locked, so we do not need The auto-inc mutex in the table_share is locked, so we do not need
to have the handlers locked. to have the handlers locked.
HA_STATUS_NO_LOCK is not checked, since we cannot skip locking HA_STATUS_NO_LOCK is not checked, since we cannot skip locking
@ -6435,6 +6607,10 @@ void ha_partition::get_dynamic_partition_info(PARTITION_STATS *stat_info,
ensure disk based tables are flushed at end of query execution. ensure disk based tables are flushed at end of query execution.
Currently is never used. Currently is never used.
HA_EXTRA_FORCE_REOPEN:
Only used by MyISAM and Archive, called when altering table,
closing tables to enforce a reopen of the table files.
2) Operations used by some non-MyISAM handlers 2) Operations used by some non-MyISAM handlers
---------------------------------------------- ----------------------------------------------
HA_EXTRA_KEYREAD_PRESERVE_FIELDS: HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
@ -6559,6 +6735,9 @@ void ha_partition::get_dynamic_partition_info(PARTITION_STATS *stat_info,
HA_EXTRA_PREPARE_FOR_RENAME: HA_EXTRA_PREPARE_FOR_RENAME:
Informs the handler we are about to attempt a rename of the table. Informs the handler we are about to attempt a rename of the table.
For handlers that have share open files (MyISAM key-file and
Archive writer) they must close the files before rename is possible
on Windows.
HA_EXTRA_READCHECK: HA_EXTRA_READCHECK:
HA_EXTRA_NO_READCHECK: HA_EXTRA_NO_READCHECK:
@ -6579,10 +6758,6 @@ void ha_partition::get_dynamic_partition_info(PARTITION_STATS *stat_info,
HA_EXTRA_NO_READCHECK=5 No readcheck on update HA_EXTRA_NO_READCHECK=5 No readcheck on update
HA_EXTRA_READCHECK=6 Use readcheck (def) HA_EXTRA_READCHECK=6 Use readcheck (def)
HA_EXTRA_FORCE_REOPEN:
Only used by MyISAM, called when altering table, closing tables to
enforce a reopen of the table files.
4) Operations only used by temporary tables for query processing 4) Operations only used by temporary tables for query processing
---------------------------------------------------------------- ----------------------------------------------------------------
HA_EXTRA_RESET_STATE: HA_EXTRA_RESET_STATE:
@ -6691,6 +6866,10 @@ int ha_partition::extra(enum ha_extra_function operation)
case HA_EXTRA_FLUSH: case HA_EXTRA_FLUSH:
case HA_EXTRA_PREPARE_FOR_FORCED_CLOSE: case HA_EXTRA_PREPARE_FOR_FORCED_CLOSE:
DBUG_RETURN(loop_extra(operation)); DBUG_RETURN(loop_extra(operation));
case HA_EXTRA_PREPARE_FOR_RENAME:
case HA_EXTRA_FORCE_REOPEN:
DBUG_RETURN(loop_extra_alter(operation));
break;
/* Category 2), used by non-MyISAM handlers */ /* Category 2), used by non-MyISAM handlers */
case HA_EXTRA_IGNORE_DUP_KEY: case HA_EXTRA_IGNORE_DUP_KEY:
@ -6703,9 +6882,6 @@ int ha_partition::extra(enum ha_extra_function operation)
} }
/* Category 3), used by MyISAM handlers */ /* Category 3), used by MyISAM handlers */
case HA_EXTRA_PREPARE_FOR_RENAME:
DBUG_RETURN(prepare_for_rename());
break;
case HA_EXTRA_PREPARE_FOR_UPDATE: case HA_EXTRA_PREPARE_FOR_UPDATE:
/* /*
Needs to be run on the first partition in the range now, and Needs to be run on the first partition in the range now, and
@ -6722,7 +6898,6 @@ int ha_partition::extra(enum ha_extra_function operation)
break; break;
case HA_EXTRA_NORMAL: case HA_EXTRA_NORMAL:
case HA_EXTRA_QUICK: case HA_EXTRA_QUICK:
case HA_EXTRA_FORCE_REOPEN:
case HA_EXTRA_PREPARE_FOR_DROP: case HA_EXTRA_PREPARE_FOR_DROP:
case HA_EXTRA_FLUSH_CACHE: case HA_EXTRA_FLUSH_CACHE:
{ {
@ -6827,18 +7002,17 @@ int ha_partition::extra(enum ha_extra_function operation)
} }
/* /**
Special extra call to reset extra parameters Special extra call to reset extra parameters
SYNOPSIS @return Operation status.
reset() @retval >0 Error code
@retval 0 Success
RETURN VALUE @note Called at end of each statement to reset buffers.
>0 Error code To avoid excessive calls, the m_partitions_to_reset bitmap keep records
0 Success of which partitions that have been used in extra(), external_lock() or
start_stmt() and is needed to be called.
DESCRIPTION
Called at end of each statement to reset buffers
*/ */
int ha_partition::reset(void) int ha_partition::reset(void)
@ -6902,41 +7076,48 @@ void ha_partition::prepare_extra_cache(uint cachesize)
m_extra_cache_size= cachesize; m_extra_cache_size= cachesize;
if (m_part_spec.start_part != NO_CURRENT_PART_ID) if (m_part_spec.start_part != NO_CURRENT_PART_ID)
{ {
DBUG_ASSERT(bitmap_is_set(&m_partitions_to_reset,
m_part_spec.start_part));
bitmap_set_bit(&m_partitions_to_reset, m_part_spec.start_part);
late_extra_cache(m_part_spec.start_part); late_extra_cache(m_part_spec.start_part);
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
/* /**
Prepares our new and reorged handlers for rename or delete Prepares our new and reorged handlers for rename or delete.
SYNOPSIS @param operation Operation to forward
prepare_for_delete()
RETURN VALUE @return Operation status
>0 Error code @retval 0 Success
0 Success @retval !0 Error
*/ */
int ha_partition::prepare_for_rename() int ha_partition::loop_extra_alter(enum ha_extra_function operation)
{ {
int result= 0, tmp; int result= 0, tmp;
handler **file; handler **file;
DBUG_ENTER("ha_partition::prepare_for_rename()"); DBUG_ENTER("ha_partition::loop_extra_alter()");
DBUG_ASSERT(operation == HA_EXTRA_PREPARE_FOR_RENAME ||
operation == HA_EXTRA_FORCE_REOPEN);
if (m_new_file != NULL) if (m_new_file != NULL)
{ {
for (file= m_new_file; *file; file++) for (file= m_new_file; *file; file++)
if ((tmp= (*file)->extra(HA_EXTRA_PREPARE_FOR_RENAME))) if ((tmp= (*file)->extra(operation)))
result= tmp; result= tmp;
for (file= m_reorged_file; *file; file++)
if ((tmp= (*file)->extra(HA_EXTRA_PREPARE_FOR_RENAME)))
result= tmp;
DBUG_RETURN(result);
} }
if (m_reorged_file != NULL)
DBUG_RETURN(loop_extra(HA_EXTRA_PREPARE_FOR_RENAME)); {
for (file= m_reorged_file; *file; file++)
if ((tmp= (*file)->extra(operation)))
result= tmp;
}
if ((tmp= loop_extra(operation)))
result= tmp;
DBUG_RETURN(result);
} }
/* /*
@ -7350,6 +7531,31 @@ uint8 ha_partition::table_cache_type()
} }
/**
Calculate hash value for KEY partitioning using an array of fields.
@param field_array An array of the fields in KEY partitioning
@return hash_value calculated
@note Uses the hash function on the character set of the field.
Integer and floating point fields use the binary character set by default.
*/
uint32 ha_partition::calculate_key_hash_value(Field **field_array)
{
ulong nr1= 1;
ulong nr2= 4;
do
{
Field *field= *field_array;
field->hash(&nr1, &nr2);
} while (*(++field_array));
return (uint32) nr1;
}
/**************************************************************************** /****************************************************************************
MODULE print messages MODULE print messages
****************************************************************************/ ****************************************************************************/
@ -7373,17 +7579,29 @@ const char *ha_partition::index_type(uint inx)
enum row_type ha_partition::get_row_type() const enum row_type ha_partition::get_row_type() const
{ {
handler **file; uint i;
enum row_type type= (*m_file)->get_row_type(); enum row_type type;
DBUG_ENTER("ha_partition::get_row_type");
for (file= m_file, file++; *file; file++) i= bitmap_get_first_set(&m_part_info->read_partitions);
DBUG_ASSERT(i < m_tot_parts);
if (i >= m_tot_parts)
DBUG_RETURN(ROW_TYPE_NOT_USED);
type= m_file[i]->get_row_type();
DBUG_PRINT("info", ("partition %u, row_type: %d", i, type));
for (i= bitmap_get_next_set(&m_part_info->lock_partitions, i);
i < m_tot_parts;
i= bitmap_get_next_set(&m_part_info->lock_partitions, i))
{ {
enum row_type part_type= (*file)->get_row_type(); enum row_type part_type= m_file[i]->get_row_type();
DBUG_PRINT("info", ("partition %u, row_type: %d", i, type));
if (part_type != type) if (part_type != type)
return ROW_TYPE_NOT_USED; DBUG_RETURN(ROW_TYPE_NOT_USED);
} }
return type; DBUG_RETURN(type);
} }
@ -7434,47 +7652,46 @@ bool ha_partition::get_error_message(int error, String *buf)
/**************************************************************************** /****************************************************************************
MODULE in-place ALTER MODULE in-place ALTER
****************************************************************************/ ****************************************************************************/
/**
Get table flags.
*/
handler::Table_flags ha_partition::table_flags() const
{
uint first_used_partition= 0;
DBUG_ENTER("ha_partition::table_flags");
if (m_handler_status < handler_initialized ||
m_handler_status >= handler_closed)
DBUG_RETURN(PARTITION_ENABLED_TABLE_FLAGS);
if (get_lock_type() != F_UNLCK)
{
/*
The flags are cached after external_lock, and may depend on isolation
level. So we should use a locked partition to get the correct flags.
*/
first_used_partition= bitmap_get_first_set(&m_part_info->lock_partitions);
if (first_used_partition == MY_BIT_NONE)
first_used_partition= 0;
}
DBUG_RETURN((m_file[first_used_partition]->ha_table_flags() &
~(PARTITION_DISABLED_TABLE_FLAGS)) |
(PARTITION_ENABLED_TABLE_FLAGS));
}
/** /**
alter_table_flags must be on handler/table level, not on hton level alter_table_flags must be on handler/table level, not on hton level
due to the ha_partition hton does not know what the underlying hton is. due to the ha_partition hton does not know what the underlying hton is.
*/ */
uint ha_partition::alter_table_flags(uint flags) uint ha_partition::alter_table_flags(uint flags)
{ {
uint flags_to_return, flags_to_check; uint flags_to_return;
DBUG_ENTER("ha_partition::alter_table_flags"); DBUG_ENTER("ha_partition::alter_table_flags");
flags_to_return= ht->alter_table_flags(flags); flags_to_return= ht->alter_table_flags(flags);
flags_to_return|= m_file[0]->alter_table_flags(flags); flags_to_return|= m_file[0]->alter_table_flags(flags);
/*
If one partition fails we must be able to revert the change for the other,
already altered, partitions. So both ADD and DROP can only be supported in
pairs.
*/
flags_to_check= HA_INPLACE_ADD_INDEX_NO_READ_WRITE;
flags_to_check|= HA_INPLACE_DROP_INDEX_NO_READ_WRITE;
if ((flags_to_return & flags_to_check) != flags_to_check)
flags_to_return&= ~flags_to_check;
flags_to_check= HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE;
flags_to_check|= HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE;
if ((flags_to_return & flags_to_check) != flags_to_check)
flags_to_return&= ~flags_to_check;
flags_to_check= HA_INPLACE_ADD_PK_INDEX_NO_READ_WRITE;
flags_to_check|= HA_INPLACE_DROP_PK_INDEX_NO_READ_WRITE;
if ((flags_to_return & flags_to_check) != flags_to_check)
flags_to_return&= ~flags_to_check;
flags_to_check= HA_INPLACE_ADD_INDEX_NO_WRITE;
flags_to_check|= HA_INPLACE_DROP_INDEX_NO_WRITE;
if ((flags_to_return & flags_to_check) != flags_to_check)
flags_to_return&= ~flags_to_check;
flags_to_check= HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE;
flags_to_check|= HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE;
if ((flags_to_return & flags_to_check) != flags_to_check)
flags_to_return&= ~flags_to_check;
flags_to_check= HA_INPLACE_ADD_PK_INDEX_NO_WRITE;
flags_to_check|= HA_INPLACE_DROP_PK_INDEX_NO_WRITE;
if ((flags_to_return & flags_to_check) != flags_to_check)
flags_to_return&= ~flags_to_check;
DBUG_RETURN(flags_to_return); DBUG_RETURN(flags_to_return);
} }
@ -8096,7 +8313,6 @@ void ha_partition::release_auto_increment()
DBUG_PRINT("info", ("part_share->next_auto_inc_val: %lu", DBUG_PRINT("info", ("part_share->next_auto_inc_val: %lu",
(ulong) part_share->next_auto_inc_val)); (ulong) part_share->next_auto_inc_val));
/* Unlock the multi row statement lock taken in get_auto_increment */ /* Unlock the multi row statement lock taken in get_auto_increment */
if (auto_increment_safe_stmt_log_lock) if (auto_increment_safe_stmt_log_lock)
{ {
@ -8119,6 +8335,27 @@ void ha_partition::init_table_handle_for_HANDLER()
} }
/**
Return the checksum of the table (all partitions)
*/
uint ha_partition::checksum() const
{
ha_checksum sum= 0;
DBUG_ENTER("ha_partition::checksum");
if ((table_flags() & (HA_HAS_OLD_CHECKSUM | HA_HAS_NEW_CHECKSUM)))
{
handler **file= m_file;
do
{
sum+= (*file)->checksum();
} while (*(++file));
}
DBUG_RETURN(sum);
}
/**************************************************************************** /****************************************************************************
MODULE enable/disable indexes MODULE enable/disable indexes
****************************************************************************/ ****************************************************************************/

View File

@ -3,49 +3,32 @@
/* /*
Copyright (c) 2005, 2012, Oracle and/or its affiliates. Copyright (c) 2005, 2012, Oracle and/or its affiliates.
Copyright (c) 2009-2013 Monty Program Ab & SkySQL Ab
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License. the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#ifdef __GNUC__
#pragma interface /* gcc class implementation */
#endif
#include "sql_partition.h" /* part_id_range, partition_element */ #include "sql_partition.h" /* part_id_range, partition_element */
#include "queues.h" /* QUEUE */ #include "queues.h" /* QUEUE */
enum partition_keywords enum partition_keywords
{ {
PKW_HASH= 0, PKW_RANGE, PKW_LIST, PKW_KEY, PKW_MAXVALUE, PKW_LINEAR, PKW_HASH= 0, PKW_RANGE, PKW_LIST, PKW_KEY, PKW_MAXVALUE, PKW_LINEAR,
PKW_COLUMNS PKW_COLUMNS
}; };
#define PARTITION_BYTES_IN_POS 2 #define PARTITION_BYTES_IN_POS 2
#define PARTITION_ENABLED_TABLE_FLAGS (HA_FILE_BASED | HA_REC_NOT_IN_SEQ)
#define PARTITION_DISABLED_TABLE_FLAGS (HA_CAN_GEOMETRY | \
HA_CAN_FULLTEXT | \
HA_DUPLICATE_POS | \
HA_CAN_SQL_HANDLER | \
HA_CAN_INSERT_DELAYED)
/* First 4 bytes in the .par file is the number of 32-bit words in the file */
#define PAR_WORD_SIZE 4
/* offset to the .par file checksum */
#define PAR_CHECKSUM_OFFSET 4
/* offset to the total number of partitions */
#define PAR_NUM_PARTS_OFFSET 8
/* offset to the engines array */
#define PAR_ENGINES_OFFSET 12
/** Struct used for partition_name_hash */ /** Struct used for partition_name_hash */
typedef struct st_part_name_def typedef struct st_part_name_def
@ -148,7 +131,7 @@ private:
/* Data for the partition handler */ /* Data for the partition handler */
int m_mode; // Open mode int m_mode; // Open mode
uint m_open_test_lock; // Open test_if_locked uint m_open_test_lock; // Open test_if_locked
char *m_file_buffer; // Content of the .par file uchar *m_file_buffer; // Content of the .par file
char *m_name_buffer_ptr; // Pointer to first partition name char *m_name_buffer_ptr; // Pointer to first partition name
MEM_ROOT m_mem_root; MEM_ROOT m_mem_root;
plugin_ref *m_engine_array; // Array of types of the handlers plugin_ref *m_engine_array; // Array of types of the handlers
@ -191,8 +174,6 @@ private:
uint m_tot_parts; // Total number of partitions; uint m_tot_parts; // Total number of partitions;
uint m_num_locks; // For engines like ha_blackhole, which needs no locks uint m_num_locks; // For engines like ha_blackhole, which needs no locks
uint m_last_part; // Last file that we update,write,read uint m_last_part; // Last file that we update,write,read
int m_lock_type; // Remembers type of last
// external_lock
part_id_range m_part_spec; // Which parts to scan part_id_range m_part_spec; // Which parts to scan
uint m_scan_value; // Value passed in rnd_init uint m_scan_value; // Value passed in rnd_init
// call // call
@ -356,7 +337,6 @@ public:
virtual bool check_if_incompatible_data(HA_CREATE_INFO *create_info, virtual bool check_if_incompatible_data(HA_CREATE_INFO *create_info,
uint table_changes); uint table_changes);
private: private:
int prepare_for_rename();
int copy_partitions(ulonglong * const copied, ulonglong * const deleted); int copy_partitions(ulonglong * const copied, ulonglong * const deleted);
void cleanup_new_partition(uint part_count); void cleanup_new_partition(uint part_count);
int prepare_new_partition(TABLE *table, HA_CREATE_INFO *create_info, int prepare_new_partition(TABLE *table, HA_CREATE_INFO *create_info,
@ -390,6 +370,7 @@ private:
bool populate_partition_name_hash(); bool populate_partition_name_hash();
Partition_share *get_share(); Partition_share *get_share();
bool set_ha_share_ref(Handler_share **ha_share); bool set_ha_share_ref(Handler_share **ha_share);
void fix_data_dir(char* path);
bool init_partition_bitmaps(); bool init_partition_bitmaps();
void free_partition_bitmaps(); void free_partition_bitmaps();
@ -409,8 +390,6 @@ public:
If the object was opened it will also be closed before being deleted. If the object was opened it will also be closed before being deleted.
*/ */
virtual int open(const char *name, int mode, uint test_if_locked); virtual int open(const char *name, int mode, uint test_if_locked);
virtual void unbind_psi();
virtual void rebind_psi();
virtual int close(void); virtual int close(void);
/* /*
@ -452,6 +431,18 @@ public:
*/ */
virtual void try_semi_consistent_read(bool); virtual void try_semi_consistent_read(bool);
/*
NOTE: due to performance and resource issues with many partitions,
we only use the m_psi on the ha_partition handler, excluding all
partitions m_psi.
*/
#ifdef HAVE_M_PSI_PER_PARTITION
/*
Bind the table/handler thread to track table i/o.
*/
virtual void unbind_psi();
virtual void rebind_psi();
#endif
/* /*
------------------------------------------------------------------------- -------------------------------------------------------------------------
MODULE change record MODULE change record
@ -502,6 +493,7 @@ public:
return FALSE; return FALSE;
return TRUE; return TRUE;
} }
/* /*
------------------------------------------------------------------------- -------------------------------------------------------------------------
MODULE full table scan MODULE full table scan
@ -626,7 +618,6 @@ private:
int handle_ordered_next(uchar * buf, bool next_same); int handle_ordered_next(uchar * buf, bool next_same);
int handle_ordered_prev(uchar * buf); int handle_ordered_prev(uchar * buf);
void return_top_record(uchar * buf); void return_top_record(uchar * buf);
void column_bitmaps_signal();
public: public:
/* /*
------------------------------------------------------------------------- -------------------------------------------------------------------------
@ -659,6 +650,7 @@ private:
handler *file, uint *n); handler *file, uint *n);
static const uint NO_CURRENT_PART_ID; static const uint NO_CURRENT_PART_ID;
int loop_extra(enum ha_extra_function operation); int loop_extra(enum ha_extra_function operation);
int loop_extra_alter(enum ha_extra_function operations);
void late_extra_cache(uint partition_id); void late_extra_cache(uint partition_id);
void late_extra_no_cache(uint partition_id); void late_extra_no_cache(uint partition_id);
void prepare_extra_cache(uint cachesize); void prepare_extra_cache(uint cachesize);
@ -727,6 +719,9 @@ public:
virtual uint8 table_cache_type(); virtual uint8 table_cache_type();
virtual ha_rows records(); virtual ha_rows records();
/* Calculate hash value for PARTITION BY KEY tables. */
uint32 calculate_key_hash_value(Field **field_array);
/* /*
------------------------------------------------------------------------- -------------------------------------------------------------------------
MODULE print messages MODULE print messages
@ -742,6 +737,9 @@ public:
*/ */
virtual const char *index_type(uint inx); 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;
/* The name of the row type used for the underlying tables. */ /* The name of the row type used for the underlying tables. */
virtual enum row_type get_row_type() const; virtual enum row_type get_row_type() const;
@ -903,17 +901,7 @@ public:
HA_CAN_INSERT_DELAYED, HA_PRIMARY_KEY_REQUIRED_FOR_POSITION is disabled HA_CAN_INSERT_DELAYED, HA_PRIMARY_KEY_REQUIRED_FOR_POSITION is disabled
until further investigated. until further investigated.
*/ */
virtual Table_flags table_flags() const virtual Table_flags table_flags() const;
{
DBUG_ENTER("ha_partition::table_flags");
if (m_handler_status < handler_initialized ||
m_handler_status >= handler_closed)
DBUG_RETURN(PARTITION_ENABLED_TABLE_FLAGS);
DBUG_RETURN((m_file[0]->ha_table_flags() &
~(PARTITION_DISABLED_TABLE_FLAGS)) |
(PARTITION_ENABLED_TABLE_FLAGS));
}
/* /*
This is a bitmap of flags that says how the storage engine This is a bitmap of flags that says how the storage engine
@ -1153,10 +1141,10 @@ public:
/* /*
------------------------------------------------------------------------- -------------------------------------------------------------------------
MODULE in-place ALTER TABLE MODULE in-place ALTER TABLE
------------------------------------------------------------------------- -------------------------------------------------------------------------
These methods are in the handler interface. (used by innodb-plugin) These methods are in the handler interface. (used by innodb-plugin)
They are used for in-place alter table: They are used for in-place alter table:
------------------------------------------------------------------------- -------------------------------------------------------------------------
*/ */
virtual enum_alter_inplace_result virtual enum_alter_inplace_result
check_if_supported_inplace_alter(TABLE *altered_table, check_if_supported_inplace_alter(TABLE *altered_table,
@ -1170,7 +1158,7 @@ public:
bool commit); bool commit);
virtual void notify_table_changed(); virtual void notify_table_changed();
/* /*
------------------------------------------------------------------------- -------------------------------------------------------------------------
MODULE tablespace support MODULE tablespace support
------------------------------------------------------------------------- -------------------------------------------------------------------------
@ -1213,8 +1201,8 @@ public:
virtual int restore(THD* thd, HA_CHECK_OPT *check_opt); virtual int restore(THD* thd, HA_CHECK_OPT *check_opt);
virtual int dump(THD* thd, int fd = -1); virtual int dump(THD* thd, int fd = -1);
virtual int net_read_dump(NET* net); virtual int net_read_dump(NET* net);
virtual uint checksum() const;
*/ */
virtual uint checksum() const;
/* Enabled keycache for performance reasons, WL#4571 */ /* Enabled keycache for performance reasons, WL#4571 */
virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt); virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt);
virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt); virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt);

View File

@ -2237,6 +2237,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
handler *handler::clone(const char *name, MEM_ROOT *mem_root) handler *handler::clone(const char *name, MEM_ROOT *mem_root)
{ {
handler *new_handler= get_new_handler(table->s, mem_root, ht); handler *new_handler= get_new_handler(table->s, mem_root, ht);
if (!new_handler) if (!new_handler)
return NULL; return NULL;
if (new_handler->set_ha_share_ref(ha_share)) if (new_handler->set_ha_share_ref(ha_share))
@ -5047,14 +5048,7 @@ int handler::read_range_first(const key_range *start_key,
DBUG_ENTER("handler::read_range_first"); DBUG_ENTER("handler::read_range_first");
eq_range= eq_range_arg; eq_range= eq_range_arg;
end_range= 0; set_end_range(end_key);
if (end_key)
{
end_range= &save_end_range;
save_end_range= *end_key;
key_compare_result_on_equal= ((end_key->flag == HA_READ_BEFORE_KEY) ? 1 :
(end_key->flag == HA_READ_AFTER_KEY) ? -1 : 0);
}
range_key_part= table->key_info[active_index].key_part; range_key_part= table->key_info[active_index].key_part;
if (!start_key) // Read first record if (!start_key) // Read first record
@ -5130,12 +5124,26 @@ int handler::read_range_next()
} }
void handler::set_end_range(const key_range *end_key)
{
end_range= 0;
if (end_key)
{
end_range= &save_end_range;
save_end_range= *end_key;
key_compare_result_on_equal=
((end_key->flag == HA_READ_BEFORE_KEY) ? 1 :
(end_key->flag == HA_READ_AFTER_KEY) ? -1 : 0);
}
}
/** /**
Compare if found key (in row) is over max-value. Compare if found key (in row) is over max-value.
@param range range to compare to row. May be 0 for no range @param range range to compare to row. May be 0 for no range
@seealso @see also
key.cc::key_cmp() key.cc::key_cmp()
@return @return

View File

@ -2809,6 +2809,7 @@ public:
const key_range *end_key, const key_range *end_key,
bool eq_range, bool sorted); bool eq_range, bool sorted);
virtual int read_range_next(); virtual int read_range_next();
void set_end_range(const key_range *end_key);
int compare_key(key_range *range); int compare_key(key_range *range);
int compare_key2(key_range *range); int compare_key2(key_range *range);
virtual int ft_init() { return HA_ERR_WRONG_COMMAND; } virtual int ft_init() { return HA_ERR_WRONG_COMMAND; }

View File

@ -312,8 +312,8 @@ bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock, uint flags)
thd_proc_info(thd, "Table lock"); thd_proc_info(thd, "Table lock");
/* Copy the lock data array. thr_multi_lock() reorders its contents. */ /* Copy the lock data array. thr_multi_lock() reorders its contents. */
memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks, memmove(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
sql_lock->lock_count * sizeof(*sql_lock->locks)); sql_lock->lock_count * sizeof(*sql_lock->locks));
/* Lock on the copied half of the lock data array. */ /* Lock on the copied half of the lock data array. */
rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks + rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
sql_lock->lock_count, sql_lock->lock_count,
@ -692,7 +692,7 @@ static int unlock_external(THD *thd, TABLE **table,uint count)
MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags) MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
{ {
uint i,tables,lock_count; uint i,lock_count,table_count;
MYSQL_LOCK *sql_lock; MYSQL_LOCK *sql_lock;
THR_LOCK_DATA **locks, **locks_buf; THR_LOCK_DATA **locks, **locks_buf;
TABLE **to, **table_buf; TABLE **to, **table_buf;
@ -701,15 +701,15 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
DBUG_ASSERT((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS)); DBUG_ASSERT((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
DBUG_PRINT("info", ("count %d", count)); DBUG_PRINT("info", ("count %d", count));
for (i=tables=lock_count=0 ; i < count ; i++) for (i=lock_count=table_count=0 ; i < count ; i++)
{ {
TABLE *t= table_ptr[i]; TABLE *t= table_ptr[i];
if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE && if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE &&
t->s->tmp_table != INTERNAL_TMP_TABLE) t->s->tmp_table != INTERNAL_TMP_TABLE)
{ {
tables+= t->file->lock_count(); lock_count+= t->file->lock_count();
lock_count++; table_count++;
} }
} }
@ -721,13 +721,13 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
*/ */
if (!(sql_lock= (MYSQL_LOCK*) if (!(sql_lock= (MYSQL_LOCK*)
my_malloc(sizeof(*sql_lock) + my_malloc(sizeof(*sql_lock) +
sizeof(THR_LOCK_DATA*) * tables * 2 + sizeof(THR_LOCK_DATA*) * lock_count * 2 +
sizeof(table_ptr) * lock_count, sizeof(table_ptr) * table_count,
MYF(0)))) MYF(0))))
DBUG_RETURN(0); DBUG_RETURN(0);
locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1); locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
to= table_buf= sql_lock->table= (TABLE**) (locks + tables * 2); to= table_buf= sql_lock->table= (TABLE**) (locks + lock_count * 2);
sql_lock->table_count=lock_count; sql_lock->table_count= table_count;
for (i=0 ; i < count ; i++) for (i=0 ; i < count ; i++)
{ {
@ -763,7 +763,7 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
} }
} }
/* /*
We do not use 'tables', because there are cases where store_lock() We do not use 'lock_count', because there are cases where store_lock()
returns less locks than lock_count() claimed. This can happen when returns less locks than lock_count() claimed. This can happen when
a FLUSH TABLES tries to abort locks from a MERGE table of another a FLUSH TABLES tries to abort locks from a MERGE table of another
thread. When that thread has just opened the table, but not yet thread. When that thread has just opened the table, but not yet
@ -777,6 +777,7 @@ MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, uint flags)
And in the FLUSH case, the memory is released quickly anyway. And in the FLUSH case, the memory is released quickly anyway.
*/ */
sql_lock->lock_count= locks - locks_buf; sql_lock->lock_count= locks - locks_buf;
DBUG_ASSERT(sql_lock->lock_count <= lock_count);
DBUG_PRINT("info", ("sql_lock->table_count %d sql_lock->lock_count %d", DBUG_PRINT("info", ("sql_lock->table_count %d sql_lock->lock_count %d",
sql_lock->table_count, sql_lock->lock_count)); sql_lock->table_count, sql_lock->lock_count));
DBUG_RETURN(sql_lock); DBUG_RETURN(sql_lock);

View File

@ -3972,6 +3972,12 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
if (!table->file) if (!table->file)
goto err; goto err;
if (table->file->set_ha_share_ref(&share->ha_share))
{
delete table->file;
goto err;
}
null_count=1; null_count=1;
null_pack_length= 1; null_pack_length= 1;

View File

@ -1532,7 +1532,6 @@ THD::~THD()
mysql_audit_release(this); mysql_audit_release(this);
plugin_thdvar_cleanup(this); plugin_thdvar_cleanup(this);
DBUG_PRINT("info", ("freeing security context"));
main_security_ctx.destroy(); main_security_ctx.destroy();
my_free(db); my_free(db);
db= NULL; db= NULL;
@ -3801,6 +3800,7 @@ void Security_context::init()
void Security_context::destroy() void Security_context::destroy()
{ {
DBUG_PRINT("info", ("freeing security context"));
// If not pointer to constant // If not pointer to constant
if (host != my_localhost) if (host != my_localhost)
{ {

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2000, 2012, Oracle and/or its affiliates. Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2009, 2012, Monty Program Ab Copyright (c) 2009-2013, Monty Program Ab & SkySQL Ab
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -465,6 +465,8 @@ class Time_zone;
#define THD_CHECK_SENTRY(thd) DBUG_ASSERT(thd->dbug_sentry == THD_SENTRY_MAGIC) #define THD_CHECK_SENTRY(thd) DBUG_ASSERT(thd->dbug_sentry == THD_SENTRY_MAGIC)
typedef ulonglong sql_mode_t;
typedef struct system_variables typedef struct system_variables
{ {
/* /*
@ -488,7 +490,7 @@ typedef struct system_variables
ulonglong tmp_table_size; ulonglong tmp_table_size;
ulonglong long_query_time; ulonglong long_query_time;
ulonglong optimizer_switch; ulonglong optimizer_switch;
ulonglong sql_mode; ///< which non-standard SQL behaviour should be enabled sql_mode_t sql_mode; ///< which non-standard SQL behaviour should be enabled
ulonglong option_bits; ///< OPTION_xxx constants, e.g. OPTION_PROFILING ulonglong option_bits; ///< OPTION_xxx constants, e.g. OPTION_PROFILING
ulonglong join_buff_space_limit; ulonglong join_buff_space_limit;
ulonglong log_slow_filter; ulonglong log_slow_filter;
@ -2618,8 +2620,8 @@ public:
inline bool is_strict_mode() const inline bool is_strict_mode() const
{ {
return variables.sql_mode & (MODE_STRICT_TRANS_TABLES | return (bool) (variables.sql_mode & (MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES); MODE_STRICT_ALL_TABLES));
} }
inline my_time_t query_start() { query_start_used=1; return start_time; } inline my_time_t query_start() { query_start_used=1; return start_time; }
inline ulong query_start_sec_part() inline ulong query_start_sec_part()
@ -3417,7 +3419,7 @@ my_eof(THD *thd)
const my_bool strict_date_checking= 0; const my_bool strict_date_checking= 0;
inline ulonglong sql_mode_for_dates(THD *thd) inline sql_mode_t sql_mode_for_dates(THD *thd)
{ {
if (strict_date_checking) if (strict_date_checking)
return (thd->variables.sql_mode & return (thd->variables.sql_mode &
@ -3426,7 +3428,7 @@ inline ulonglong sql_mode_for_dates(THD *thd)
return (thd->variables.sql_mode & MODE_INVALID_DATES); return (thd->variables.sql_mode & MODE_INVALID_DATES);
} }
inline ulonglong sql_mode_for_dates() inline sql_mode_t sql_mode_for_dates()
{ {
return sql_mode_for_dates(current_thd); return sql_mode_for_dates(current_thd);
} }

View File

@ -1995,6 +1995,79 @@ static int add_quoted_string(File fptr, const char *quotestr)
return err + add_string(fptr, "'"); return err + add_string(fptr, "'");
} }
/**
@brief Truncate the partition file name from a path it it exists.
@note A partition file name will contian one or more '#' characters.
One of the occurances of '#' will be either "#P#" or "#p#" depending
on whether the storage engine has converted the filename to lower case.
*/
void truncate_partition_filename(char *path)
{
if (path)
{
char* last_slash= strrchr(path, FN_LIBCHAR);
if (!last_slash)
last_slash= strrchr(path, FN_LIBCHAR2);
if (last_slash)
{
/* Look for a partition-type filename */
for (char* pound= strchr(last_slash, '#');
pound; pound = strchr(pound + 1, '#'))
{
if ((pound[1] == 'P' || pound[1] == 'p') && pound[2] == '#')
{
last_slash[0] = '\0'; /* truncate the file name */
break;
}
}
}
}
}
/**
@brief Output a filepath. Similar to add_keyword_string except it
also converts \ to / on Windows and skips the partition file name at
the end if found.
@note
When Mysql sends a DATA DIRECTORY from SQL for partitions it does
not use a file name, but it does for DATA DIRECTORY on a non-partitioned
table. So when the storage engine is asked for the DATA DIRECTORY string
after a restart through Handler::update_create_options(), the storage
engine may include the filename.
*/
static int add_keyword_path(File fptr, const char *keyword,
const char *path)
{
char temp_path[FN_REFLEN];
int err= add_string(fptr, keyword);
err+= add_space(fptr);
err+= add_equal(fptr);
err+= add_space(fptr);
strmake(temp_path, path, sizeof(temp_path)-1);
/* Convert \ to / to be able to create table on unix */
to_unix_path(temp_path);
/*
If the partition file name with its "#P#" identifier
is found after the last slash, truncate that filename.
*/
truncate_partition_filename(temp_path);
err+= add_quoted_string(fptr, temp_path);
return err + add_space(fptr);
}
static int add_keyword_string(File fptr, const char *keyword, static int add_keyword_string(File fptr, const char *keyword,
bool should_use_quotes, bool should_use_quotes,
const char *keystr) const char *keystr)
@ -2047,11 +2120,9 @@ static int add_partition_options(File fptr, partition_element *p_elem)
if (!(current_thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) if (!(current_thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
{ {
if (p_elem->data_file_name) if (p_elem->data_file_name)
err+= add_keyword_string(fptr, "DATA DIRECTORY", TRUE, err+= add_keyword_path(fptr, "DATA DIRECTORY", p_elem->data_file_name);
p_elem->data_file_name);
if (p_elem->index_file_name) if (p_elem->index_file_name)
err+= add_keyword_string(fptr, "INDEX DIRECTORY", TRUE, err+= add_keyword_path(fptr, "INDEX DIRECTORY", p_elem->index_file_name);
p_elem->index_file_name);
} }
if (p_elem->part_comment) if (p_elem->part_comment)
err+= add_keyword_string(fptr, "COMMENT", TRUE, p_elem->part_comment); err+= add_keyword_string(fptr, "COMMENT", TRUE, p_elem->part_comment);

View File

@ -127,6 +127,7 @@ bool check_part_func_fields(Field **ptr, bool ok_with_charsets);
bool field_is_partition_charset(Field *field); bool field_is_partition_charset(Field *field);
Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs); Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs);
void mem_alloc_error(size_t size); void mem_alloc_error(size_t size);
void truncate_partition_filename(char *path);
/* /*
A "Get next" function for partition iterator. A "Get next" function for partition iterator.

View File

@ -14677,6 +14677,12 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
if (!table->file) if (!table->file)
goto err; goto err;
if (table->file->set_ha_share_ref(&share->ha_share))
{
delete table->file;
goto err;
}
if (!using_unique_constraint) if (!using_unique_constraint)
reclength+= group_null_items; // null flag is stored separately reclength+= group_null_items; // null flag is stored separately
@ -15620,6 +15626,12 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
new_table.s->db_type()))) new_table.s->db_type())))
DBUG_RETURN(1); // End of memory DBUG_RETURN(1); // End of memory
if (new_table.file->set_ha_share_ref(&share.ha_share))
{
delete new_table.file;
DBUG_RETURN(1);
}
save_proc_info=thd->proc_info; save_proc_info=thd->proc_info;
THD_STAGE_INFO(thd, stage_converting_heap_to_myisam); THD_STAGE_INFO(thd, stage_converting_heap_to_myisam);