MDEV-11084 Select statement with partition selection against MyISAM table opens all partitions.

Now we don't open partitions if it was explicitly cpecified.
        ha_partition::m_opened_partition bitmap added to track
        partitions that were actually opened.
This commit is contained in:
Alexey Botchkov 2018-01-29 11:01:14 +04:00
parent 041a32abcd
commit b4a2baffa8
16 changed files with 252 additions and 61 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,8 @@
select * from t1 partition (p1);
x
300
select * from t1 partition (p0);
ERROR HY000: Can't find file: './test/t1.MYI' (errno: 2 "No such file or directory")
drop table t1;
Warnings:
Warning 1017 Can't find file: './test/t1.MYI' (errno: 2 "No such file or directory")

View file

@ -0,0 +1,24 @@
#
# MDEV-11084 Select statement with partition selection against MyISAM table opens all partitions.
#
--source include/have_partition.inc
let $datadir=`select @@datadir`;
# Table declared as having 2 partitions
# create table t1 (x int) egine=myisam
# partition by range columns (x)
# ( partition p0 values less than (100), partition p1 values less than (1000));
#
# But we copy only second partition. So the 'p0' can't be opened.
copy_file std_data/mdev11084.frm $datadir/test/t1.frm;
copy_file std_data/mdev11084.par $datadir/test/t1.par;
copy_file std_data/mdev11084.part1.MYD $datadir/test/t1#P#p1.MYD;
copy_file std_data/mdev11084.part1.MYI $datadir/test/t1#P#p1.MYI;
select * from t1 partition (p1);
--replace_result $datadir ./
--error ER_FILE_NOT_FOUND
select * from t1 partition (p0);
--replace_result $datadir ./
drop table t1;

View file

@ -368,6 +368,7 @@ void ha_partition::init_handler_variables()
part_share= NULL;
m_new_partitions_share_refs.empty();
m_part_ids_sorted_by_num_of_records= NULL;
m_partitions_to_open= NULL;
m_range_info= NULL;
m_mrr_full_buffer_size= 0;
@ -389,6 +390,7 @@ void ha_partition::init_handler_variables()
my_bitmap_clear(&m_partitions_to_reset);
my_bitmap_clear(&m_key_not_found_partitions);
my_bitmap_clear(&m_mrr_used_partitions);
my_bitmap_clear(&m_opened_partitions);
#ifdef DONT_HAVE_TO_BE_INITALIZED
m_start_key.flag= 0;
@ -3360,6 +3362,7 @@ void ha_partition::free_partition_bitmaps()
my_bitmap_free(&m_locked_partitions);
my_bitmap_free(&m_partitions_to_reset);
my_bitmap_free(&m_key_not_found_partitions);
my_bitmap_free(&m_opened_partitions);
my_bitmap_free(&m_mrr_used_partitions);
}
@ -3401,6 +3404,9 @@ bool ha_partition::init_partition_bitmaps()
if (bitmap_init(&m_mrr_used_partitions, NULL, m_tot_parts, TRUE))
DBUG_RETURN(true);
if (my_bitmap_init(&m_opened_partitions, NULL, m_tot_parts, FALSE))
DBUG_RETURN(true);
/* Initialize the bitmap for read/lock_partitions */
if (!m_is_clone_of)
{
@ -3437,8 +3443,8 @@ bool ha_partition::init_partition_bitmaps()
int ha_partition::open(const char *name, int mode, uint test_if_locked)
{
char *name_buffer_ptr;
int error= HA_ERR_INITIALIZATION;
handler *file_sample= NULL;
handler **file;
char name_buff[FN_REFLEN + 1];
ulonglong check_table_flags;
@ -3451,7 +3457,6 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
m_part_field_array= m_part_info->full_part_field_array;
if (get_from_handler_file(name, &table->mem_root, MY_TEST(m_is_clone_of)))
DBUG_RETURN(error);
name_buffer_ptr= m_name_buffer_ptr;
if (populate_partition_name_hash())
{
DBUG_RETURN(HA_ERR_INITIALIZATION);
@ -3473,6 +3478,9 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
if (init_partition_bitmaps())
goto err_alloc;
if ((error= m_part_info->set_partition_bitmaps(m_partitions_to_open)))
goto err_alloc;
/* Allocate memory used with MMR */
if (!(m_range_info= (void **)
my_multi_malloc(MYF(MY_WME),
@ -3498,6 +3506,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
if (m_is_clone_of)
{
uint i, alloc_len;
char *name_buffer_ptr;
DBUG_ASSERT(m_clone_mem_root);
/* Allocate an array of handler pointers for the partitions handlers. */
alloc_len= (m_tot_parts + 1) * sizeof(handler*);
@ -3507,6 +3516,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
goto err_alloc;
}
memset(m_file, 0, alloc_len);
name_buffer_ptr= m_name_buffer_ptr;
/*
Populate them by cloning the original partitions. This also opens them.
Note that file->ref is allocated too.
@ -3514,6 +3524,9 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
file= m_is_clone_of->m_file;
for (i= 0; i < m_tot_parts; i++)
{
if (!bitmap_is_set(&m_is_clone_of->m_opened_partitions, i))
continue;
if ((error= create_partition_name(name_buff, sizeof(name_buff), name,
name_buffer_ptr, NORMAL_PART_NAME, FALSE)))
goto err_handler;
@ -3524,30 +3537,18 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
file= &m_file[i];
goto err_handler;
}
if (!file_sample)
file_sample= m_file[i];
name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
bitmap_set_bit(&m_opened_partitions, i);
}
}
else
{
file= m_file;
do
{
LEX_CSTRING save_connect_string= table->s->connect_string;
if ((error= create_partition_name(name_buff, sizeof(name_buff), name,
name_buffer_ptr, NORMAL_PART_NAME, FALSE)))
goto err_handler;
if (!((*file)->ht->flags & HTON_CAN_READ_CONNECT_STRING_IN_PARTITION))
table->s->connect_string= m_connect_string[(uint)(file-m_file)];
error= (*file)->ha_open(table, name_buff, mode,
test_if_locked | HA_OPEN_NO_PSI_CALL);
table->s->connect_string= save_connect_string;
if (error)
goto err_handler;
if (m_file == file)
m_num_locks= (*file)->lock_count();
DBUG_ASSERT(m_num_locks == (*file)->lock_count());
name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
} while (*(++file));
if ((error= open_read_partitions(name_buff, sizeof(name_buff),
&file_sample)))
goto err_handler;
m_num_locks= file_sample->lock_count();
}
/*
We want to know the upper bound for locks, to allocate enough memory.
@ -3558,12 +3559,14 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
m_num_locks*= m_tot_parts;
file= m_file;
ref_length= (*file)->ref_length;
check_table_flags= (((*file)->ha_table_flags() &
ref_length= file_sample->ref_length;
check_table_flags= ((file_sample->ha_table_flags() &
~(PARTITION_DISABLED_TABLE_FLAGS)) |
(PARTITION_ENABLED_TABLE_FLAGS));
while (*(++file))
{
if (!bitmap_is_set(&m_opened_partitions, file - m_file))
continue;
/* MyISAM can have smaller ref_length for partitions with MAX_ROWS set */
set_if_bigger(ref_length, ((*file)->ref_length));
/*
@ -3580,8 +3583,8 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
goto err_handler;
}
}
key_used_on_scan= m_file[0]->key_used_on_scan;
implicit_emptied= m_file[0]->implicit_emptied;
key_used_on_scan= file_sample->key_used_on_scan;
implicit_emptied= file_sample->implicit_emptied;
/*
Add 2 bytes for partition id in position ref length.
ref_length=max_in_all_partitions(ref_length) + PARTITION_BYTES_IN_POS
@ -3612,8 +3615,12 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
err_handler:
DEBUG_SYNC(ha_thd(), "partition_open_error");
file= &m_file[m_tot_parts - 1];
while (file-- != m_file)
(*file)->ha_close();
{
if (bitmap_is_set(&m_opened_partitions, file - m_file))
(*file)->ha_close();
}
err_alloc:
free_partition_bitmaps();
my_free(m_range_info);
@ -3744,7 +3751,6 @@ int ha_partition::close(void)
DBUG_ASSERT(m_part_info);
destroy_record_priority_queue();
free_partition_bitmaps();
for (; ft_first ; ft_first= tmp_ft_info)
{
@ -3795,9 +3801,12 @@ int ha_partition::close(void)
repeat:
do
{
(*file)->ha_close();
if (!first || bitmap_is_set(&m_opened_partitions, file - m_file))
(*file)->ha_close();
} while (*(++file));
free_partition_bitmaps();
if (first && m_added_file && m_added_file[0])
{
file= m_added_file;
@ -8246,15 +8255,18 @@ int ha_partition::info(uint flag)
do
{
file= *file_array;
/* Get variables if not already done */
if (!(flag & HA_STATUS_VARIABLE) ||
!bitmap_is_set(&(m_part_info->read_partitions),
(uint)(file_array - m_file)))
file->info(HA_STATUS_VARIABLE | no_lock_flag | extra_var_flag);
if (file->stats.records > max_records)
if (bitmap_is_set(&(m_opened_partitions), (file_array - m_file)))
{
max_records= file->stats.records;
handler_instance= i;
/* Get variables if not already done */
if (!(flag & HA_STATUS_VARIABLE) ||
!bitmap_is_set(&(m_part_info->read_partitions),
(uint) (file_array - m_file)))
file->info(HA_STATUS_VARIABLE | no_lock_flag | extra_var_flag);
if (file->stats.records > max_records)
{
max_records= file->stats.records;
handler_instance= i;
}
}
i++;
} while (*(++file_array));
@ -8335,6 +8347,96 @@ void ha_partition::get_dynamic_partition_info(PARTITION_STATS *stat_info,
}
void ha_partition::set_partitions_to_open(List<String> *partition_names)
{
m_partitions_to_open= partition_names;
}
int ha_partition::open_read_partitions(char *name_buff, size_t name_buff_size,
handler **sample)
{
handler **file;
char *name_buffer_ptr;
int error;
name_buffer_ptr= m_name_buffer_ptr;
file= m_file;
*sample= NULL;
do
{
int n_file= file-m_file;
int is_open= bitmap_is_set(&m_opened_partitions, n_file);
int should_be_open= bitmap_is_set(&m_part_info->read_partitions, n_file);
if (is_open && !should_be_open)
{
if ((error= (*file)->ha_close()))
goto err_handler;
bitmap_clear_bit(&m_opened_partitions, n_file);
}
else if (!is_open && should_be_open)
{
LEX_CSTRING save_connect_string= table->s->connect_string;
if ((error= create_partition_name(name_buff, name_buff_size,
table->s->normalized_path.str,
name_buffer_ptr, NORMAL_PART_NAME, FALSE)))
goto err_handler;
if (!((*file)->ht->flags & HTON_CAN_READ_CONNECT_STRING_IN_PARTITION))
table->s->connect_string= m_connect_string[(uint)(file-m_file)];
error= (*file)->ha_open(table, name_buff, m_mode,
m_open_test_lock | HA_OPEN_NO_PSI_CALL);
table->s->connect_string= save_connect_string;
if (error)
goto err_handler;
if (!(*sample))
*sample= *file;
bitmap_set_bit(&m_opened_partitions, n_file);
}
name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
} while (*(++file));
err_handler:
return error;
}
int ha_partition::change_partitions_to_open(List<String> *partition_names)
{
char name_buff[FN_REFLEN+1];
int error= 0;
handler *sample;
if (m_is_clone_of)
return 0;
m_partitions_to_open= partition_names;
if ((error= m_part_info->set_partition_bitmaps(partition_names)))
goto err_handler;
if (m_lock_type != F_UNLCK)
{
/*
That happens after the LOCK TABLE statement.
Do nothing in this case.
*/
return 0;
}
if (bitmap_cmp(&m_opened_partitions, &m_part_info->read_partitions) != 0)
return 0;
if ((error= read_par_file(table->s->normalized_path.str)) ||
(error= open_read_partitions(name_buff, sizeof(name_buff), &sample)))
goto err_handler;
clear_handler_file();
err_handler:
return error;
}
/**
General function to prepare handler for certain behavior.
@ -8831,7 +8933,8 @@ int ha_partition::reset(void)
i < m_tot_parts;
i= bitmap_get_next_set(&m_partitions_to_reset, i))
{
if ((tmp= m_file[i]->ha_reset()))
if (bitmap_is_set(&m_opened_partitions, i) &&
(tmp= m_file[i]->ha_reset()))
result= tmp;
}
bitmap_clear_all(&m_partitions_to_reset);
@ -8948,7 +9051,12 @@ int ha_partition::loop_extra(enum ha_extra_function operation)
i < m_tot_parts;
i= bitmap_get_next_set(&m_part_info->lock_partitions, i))
{
if ((tmp= m_file[i]->extra(operation)))
/*
This can be called after an error in ha_open.
In this case calling 'extra' can crash.
*/
if (bitmap_is_set(&m_opened_partitions, i) &&
(tmp= m_file[i]->extra(operation)))
result= tmp;
}
/* Add all used partitions to be called in reset(). */

View file

@ -385,6 +385,8 @@ private:
/** partitions that returned HA_ERR_KEY_NOT_FOUND. */
MY_BITMAP m_key_not_found_partitions;
bool m_key_not_found;
List<String> *m_partitions_to_open;
MY_BITMAP m_opened_partitions;
public:
handler **get_child_handlers()
{
@ -836,6 +838,10 @@ public:
virtual int info(uint);
void get_dynamic_partition_info(PARTITION_STATS *stat_info,
uint part_id);
void set_partitions_to_open(List<String> *partition_names);
int change_partitions_to_open(List<String> *partition_names);
int open_read_partitions(char *name_buff, size_t name_buff_size,
handler **sample);
virtual int extra(enum ha_extra_function operation);
virtual int extra_opt(enum ha_extra_function operation, ulong cachesize);
virtual int reset(void);

View file

@ -2661,7 +2661,8 @@ PSI_table_share *handler::ha_table_share_psi() const
Don't wait for locks if not HA_OPEN_WAIT_IF_LOCKED is set
*/
int handler::ha_open(TABLE *table_arg, const char *name, int mode,
uint test_if_locked, MEM_ROOT *mem_root)
uint test_if_locked, MEM_ROOT *mem_root,
List<String> *partitions_to_open)
{
int error;
DBUG_ENTER("handler::ha_open");
@ -2676,6 +2677,8 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
DBUG_PRINT("info", ("old m_lock_type: %d F_UNLCK %d", m_lock_type, F_UNLCK));
DBUG_ASSERT(alloc_root_inited(&table->mem_root));
set_partitions_to_open(partitions_to_open);
if ((error=open(name,mode,test_if_locked)))
{
if ((error == EACCES || error == EROFS) && mode == O_RDWR &&

View file

@ -2990,7 +2990,7 @@ public:
/* ha_ methods: pubilc wrappers for private virtual API */
int ha_open(TABLE *table, const char *name, int mode, uint test_if_locked,
MEM_ROOT *mem_root= 0);
MEM_ROOT *mem_root= 0, List<String> *partitions_to_open=NULL);
int ha_index_init(uint idx, bool sorted)
{
DBUG_EXECUTE_IF("ha_index_init_fail", return HA_ERR_TABLE_DEF_CHANGED;);
@ -3569,6 +3569,9 @@ public:
virtual int info(uint)=0; // see my_base.h for full description
virtual void get_dynamic_partition_info(PARTITION_STATS *stat_info,
uint part_id);
virtual void set_partitions_to_open(List<String> *partition_names) {}
virtual int change_partitions_to_open(List<String> *partition_names)
{ return 0; }
virtual int extra(enum ha_extra_function operation)
{ return 0; }
virtual int extra_opt(enum ha_extra_function operation, ulong cache_size)

View file

@ -256,16 +256,16 @@ bool partition_info::set_read_partitions(List<char> *partition_names)
Prune away partitions not mentioned in the PARTITION () clause,
if used.
@param table_list Table list pointing to table to prune.
@param partition_names list of names of partitions.
@return Operation status
@retval true Failure
@retval false Success
*/
bool partition_info::prune_partition_bitmaps(TABLE_LIST *table_list)
bool partition_info::prune_partition_bitmaps(List<String> *partition_names)
{
List_iterator<String> partition_names_it(*(table_list->partition_names));
uint num_names= table_list->partition_names->elements;
List_iterator<String> partition_names_it(*(partition_names));
uint num_names= partition_names->elements;
uint i= 0;
DBUG_ENTER("partition_info::prune_partition_bitmaps");
@ -295,8 +295,7 @@ bool partition_info::prune_partition_bitmaps(TABLE_LIST *table_list)
/**
Set read/lock_partitions bitmap over non pruned partitions
@param table_list Possible TABLE_LIST which can contain
list of partition names to query
@param partition_names list of partition names to query
@return Operation status
@retval FALSE OK
@ -306,7 +305,7 @@ bool partition_info::prune_partition_bitmaps(TABLE_LIST *table_list)
@note OK to call multiple times without the need for free_bitmaps.
*/
bool partition_info::set_partition_bitmaps(TABLE_LIST *table_list)
bool partition_info::set_partition_bitmaps(List<String> *partition_names)
{
DBUG_ENTER("partition_info::set_partition_bitmaps");
@ -315,16 +314,15 @@ bool partition_info::set_partition_bitmaps(TABLE_LIST *table_list)
if (!bitmaps_are_initialized)
DBUG_RETURN(TRUE);
if (table_list &&
table_list->partition_names &&
table_list->partition_names->elements)
if (partition_names &&
partition_names->elements)
{
if (table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION)
{
my_error(ER_PARTITION_CLAUSE_ON_NONPARTITIONED, MYF(0));
DBUG_RETURN(true);
}
if (prune_partition_bitmaps(table_list))
if (prune_partition_bitmaps(partition_names))
DBUG_RETURN(TRUE);
}
else
@ -338,6 +336,27 @@ bool partition_info::set_partition_bitmaps(TABLE_LIST *table_list)
}
/**
Set read/lock_partitions bitmap over non pruned partitions
@param table_list Possible TABLE_LIST which can contain
list of partition names to query
@return Operation status
@retval FALSE OK
@retval TRUE Failed to allocate memory for bitmap or list of partitions
did not match
@note OK to call multiple times without the need for free_bitmaps.
*/
bool partition_info::set_partition_bitmaps_from_table(TABLE_LIST *table_list)
{
List<String> *partition_names= table_list ?
NULL : table_list->partition_names;
return set_partition_bitmaps(partition_names);
}
/*
Create a memory area where default partition names are stored and fill it
up with the names.

View file

@ -325,7 +325,8 @@ public:
partition_info *get_clone(THD *thd);
bool set_named_partition_bitmap(const char *part_name, uint length);
bool set_partition_bitmaps(TABLE_LIST *table_list);
bool set_partition_bitmaps(List<String> *partition_names);
bool set_partition_bitmaps_from_table(TABLE_LIST *table_list);
/* Answers the question if subpartitioning is used for a certain table */
bool is_sub_partitioned()
{
@ -386,7 +387,7 @@ private:
char *create_default_subpartition_name(THD *thd, uint subpart_no,
const char *part_name);
// FIXME: prune_partition_bitmaps() is duplicate of set_read_partitions()
bool prune_partition_bitmaps(TABLE_LIST *table_list);
bool prune_partition_bitmaps(List<String> *partition_names);
bool add_named_partition(const char *part_name, uint length);
public:
bool set_read_partitions(List<char> *partition_names);

View file

@ -1512,6 +1512,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
MDL_ticket *mdl_ticket;
TABLE_SHARE *share;
uint gts_flags;
int part_names_error=0;
DBUG_ENTER("open_table");
/*
@ -1609,6 +1610,12 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
table= best_table;
table->query_id= thd->query_id;
DBUG_PRINT("info",("Using locked table"));
if (table->part_info)
{
/* Set all [named] partitions as used. */
part_names_error=
table->file->change_partitions_to_open(table_list->partition_names);
}
goto reset;
}
/*
@ -1892,6 +1899,12 @@ retry_share:
{
DBUG_ASSERT(table->file != NULL);
MYSQL_REBIND_TABLE(table->file);
if (table->part_info)
{
/* Set all [named] partitions as used. */
part_names_error=
table->file->change_partitions_to_open(table_list->partition_names);
}
}
else
{
@ -1904,7 +1917,8 @@ retry_share:
error= open_table_from_share(thd, share, alias,
HA_OPEN_KEYFILE | HA_TRY_READ_ONLY,
EXTRA_RECORD,
thd->open_options, table, FALSE);
thd->open_options, table, FALSE,
table_list->partition_names);
if (error)
{
@ -1953,9 +1967,12 @@ retry_share:
#ifdef WITH_PARTITION_STORAGE_ENGINE
if (table->part_info)
{
/* Set all [named] partitions as used. */
if (table->part_info->set_partition_bitmaps(table_list))
/* Partitions specified were incorrect.*/
if (part_names_error)
{
table->file->print_error(part_names_error, MYF(0));
DBUG_RETURN(true);
}
}
else if (table_list->partition_names)
{

View file

@ -802,8 +802,8 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd)
DBUG_RETURN(true);
partition_names_list.push_back(str_partition_name, thd->mem_root);
}
first_table->partition_names= &partition_names_list;
if (first_table->table->part_info->set_partition_bitmaps(first_table))
if (first_table->table->
part_info->set_partition_bitmaps(&partition_names_list))
DBUG_RETURN(true);
if (lock_tables(thd, first_table, table_counter, 0))

View file

@ -3100,6 +3100,7 @@ static bool check_vcol_forward_refs(Field *field, Virtual_column_info *vcol)
prgflag READ_ALL etc..
ha_open_flags HA_OPEN_ABORT_IF_LOCKED etc..
outparam result table
partitions_to_open open only these partitions.
RETURN VALUES
0 ok
@ -3114,7 +3115,7 @@ static bool check_vcol_forward_refs(Field *field, Virtual_column_info *vcol)
enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
const char *alias, uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam,
bool is_create_table)
bool is_create_table, List<String> *partitions_to_open)
{
enum open_frm_error error;
uint records, i, bitmap_size, bitmap_count;
@ -3458,7 +3459,7 @@ partititon_err:
int ha_err= outparam->file->ha_open(outparam, share->normalized_path.str,
(db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
ha_open_flags);
ha_open_flags, 0, partitions_to_open);
if (ha_err)
{
share->open_errno= ha_err;

View file

@ -2885,7 +2885,8 @@ void init_mdl_requests(TABLE_LIST *table_list);
enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
const char *alias, uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam,
bool is_create_table);
bool is_create_table,
List<String> *partitions_to_open= NULL);
bool fix_session_vcol_expr(THD *thd, Virtual_column_info *vcol);
bool fix_session_vcol_expr_for_read(THD *thd, Field *field,
Virtual_column_info *vcol);