[Commits] 2603dc0: MDEV-11084 Select statement with partition selection against MyISAM table opens all partitions.

Alexey Botchkov holyfoot at askmonty.org
Thu Jun 1 16:40:02 EEST 2017


revision-id: 2603dc0d56ec90f308678a3c002f1b75af69f554 (mariadb-10.1.23-51-g2603dc0)
parent(s): e4d10e09cf318aad237143254c45458d16009f70
committer: Alexey Botchkov
timestamp: 2017-06-01 17:33:34 +0400
message:

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

        Now SELECT FROM t PARTITION(x) only opens the 'x' file.
        The table->partition_names parameter is sent to ha_open
        so it only opens the required partitions.
        If the table is reopened, the
        change_partition_to_open(partition_names) is called that
        closes and opens partitions specified for the query.

---
 sql/ha_partition.cc        | 112 +++++++++++++++++++++++++++++++++++++++------
 sql/ha_partition.h         |   5 ++
 sql/handler.cc             |   5 +-
 sql/handler.h              |   6 ++-
 sql/partition_info.cc      |  41 ++++++++++++-----
 sql/partition_info.h       |   5 +-
 sql/sql_base.cc            |  11 ++++-
 sql/sql_partition_admin.cc |   4 +-
 sql/table.cc               |   4 +-
 sql/table.h                |   3 +-
 10 files changed, 161 insertions(+), 35 deletions(-)

diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 29054c7..53a128c 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -374,6 +374,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;
 
 #ifdef DONT_HAVE_TO_BE_INITALIZED
   m_start_key.flag= 0;
@@ -3326,6 +3327,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);
 }
 
 
@@ -3373,6 +3375,16 @@ bool ha_partition::init_partition_bitmaps()
     DBUG_RETURN(true);
   }
   bitmap_clear_all(&m_key_not_found_partitions);
+
+  if (my_bitmap_init(&m_opened_partitions, NULL, m_tot_parts, FALSE))
+  {
+    my_bitmap_free(&m_bulk_insert_started);
+    my_bitmap_free(&m_locked_partitions);
+    my_bitmap_free(&m_partitions_to_reset);
+    my_bitmap_free(&m_key_not_found_partitions);
+    DBUG_RETURN(true);
+  }
+  bitmap_clear_all(&m_opened_partitions);
   m_key_not_found= false;
   /* Initialize the bitmap for read/lock_partitions */
   if (!m_is_clone_of)
@@ -3416,6 +3428,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
   char *name_buffer_ptr;
   int error= HA_ERR_INITIALIZATION;
   handler **file;
+  handler *file_sample= NULL;
   char name_buff[FN_REFLEN];
   ulonglong check_table_flags;
   DBUG_ENTER("ha_partition::open");
@@ -3425,6 +3438,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
   m_mode= mode;
   m_open_test_lock= 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;
@@ -3451,6 +3465,9 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
 
   DBUG_ASSERT(m_part_info);
 
+  m_part_info->set_partition_bitmaps(m_partitions_to_open);
+  bitmap_copy(&m_opened_partitions, &m_part_info->read_partitions);
+
   if (m_is_clone_of)
   {
     uint i, alloc_len;
@@ -3481,12 +3498,16 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
       }
       name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
     }
+    file_sample= m_file[0];
   }
   else
   {
-   file= m_file;
-   do
-   {
+    file= m_file;
+    do
+    {
+      if (!bitmap_is_set(&m_opened_partitions, file - m_file))
+        continue;
+
       create_partition_name(name_buff, name, name_buffer_ptr, NORMAL_PART_NAME,
                             FALSE);
       table->s->connect_string = m_connect_string[(uint)(file-m_file)];
@@ -3494,20 +3515,21 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
                                    test_if_locked | HA_OPEN_NO_PSI_CALL)))
         goto err_handler;
       bzero(&table->s->connect_string, sizeof(LEX_STRING));
-      if (m_file == file)
-        m_num_locks= (*file)->lock_count();
+      if (!file_sample)
+        m_num_locks= (file_sample= (*file))->lock_count();
       DBUG_ASSERT(m_num_locks == (*file)->lock_count());
-      name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
-    } while (*(++file));
+    } while (name_buffer_ptr+= strlen(name_buffer_ptr) + 1, *(++file));
   }
   
   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));
     /*
@@ -3524,8 +3546,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
@@ -3557,7 +3579,10 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
 err_handler:
   DEBUG_SYNC(ha_thd(), "partition_open_error");
   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();
 
@@ -3683,14 +3708,14 @@ int ha_partition::close(void)
 
   DBUG_ASSERT(table->s == table_share);
   destroy_record_priority_queue();
-  free_partition_bitmaps();
   DBUG_ASSERT(m_part_info);
   file= m_file;
 
 repeat:
   do
   {
-    (*file)->ha_close();
+    if (bitmap_is_set(&m_opened_partitions, file - m_file))
+      (*file)->ha_close();
   } while (*(++file));
 
   if (first && m_added_file && m_added_file[0])
@@ -3700,6 +3725,8 @@ int ha_partition::close(void)
     goto repeat;
   }
 
+  free_partition_bitmaps();
+
   m_handler_status= handler_closed;
   DBUG_RETURN(0);
 }
@@ -6782,6 +6809,63 @@ 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::change_partitions_to_open(List<String> *partition_names)
+{
+  char name_buff[FN_REFLEN];
+  handler **file;
+  char *name_buffer_ptr;
+  int error= 0;
+
+  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 (bitmap_cmp(&m_opened_partitions, &m_part_info->read_partitions) != 0)
+    return 0;
+
+  if ((error= read_par_file(table->s->normalized_path.str)))
+    goto err_handler;
+
+  name_buffer_ptr= m_name_buffer_ptr;
+  file= m_file;
+  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)
+      (*file)->ha_close();
+    else if (!is_open && should_be_open)
+    {
+      create_partition_name(name_buff, table->s->normalized_path.str,
+                            name_buffer_ptr, NORMAL_PART_NAME, FALSE);
+      table->s->connect_string = m_connect_string[(uint)(file-m_file)];
+      if ((error= (*file)->ha_open(table, name_buff, m_mode,
+                                   m_open_test_lock | HA_OPEN_NO_PSI_CALL)))
+        goto err_handler;
+      bzero(&table->s->connect_string, sizeof(LEX_STRING));
+    }
+  } while (name_buffer_ptr+= strlen(name_buffer_ptr) + 1, *(++file));
+  
+  bitmap_copy(&m_opened_partitions, &m_part_info->read_partitions);
+
+  clear_handler_file();
+
+err_handler:
+  return error;
+}
+
+
 /**
   General function to prepare handler for certain behavior.
 
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 3ea8d4a..d48b06b 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -281,6 +281,9 @@ class ha_partition :public handler
   /** 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:
   Partition_share *get_part_share() { return part_share; }
   handler *clone(const char *name, MEM_ROOT *mem_root);
@@ -652,6 +655,8 @@ class ha_partition :public handler
   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);
   virtual int extra(enum ha_extra_function operation);
   virtual int extra_opt(enum ha_extra_function operation, ulong cachesize);
   virtual int reset(void);
diff --git a/sql/handler.cc b/sql/handler.cc
index aa87da5..e8e6ec0 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -2483,7 +2483,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)
+                     uint test_if_locked,
+                     List<String> *partitions_to_open)
 {
   int error;
   DBUG_ENTER("handler::ha_open");
@@ -2498,6 +2499,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 &&
diff --git a/sql/handler.h b/sql/handler.h
index dad2b81..1e6de9c 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -2737,7 +2737,8 @@ class handler :public Sql_alloc
   }
   /* ha_ methods: pubilc wrappers for private virtual API */
   
-  int ha_open(TABLE *table, const char *name, int mode, uint test_if_locked);
+  int ha_open(TABLE *table, const char *name, int mode, uint test_if_locked,
+              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;);
@@ -3197,6 +3198,9 @@ class handler :public Sql_alloc
   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)
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index bc0db9e..7fb8f70 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -199,16 +199,16 @@ bool partition_info::set_named_partition_bitmap(const char *part_name,
   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");
 
@@ -238,8 +238,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
@@ -249,7 +248,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");
 
@@ -259,16 +258,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
@@ -283,6 +281,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);
+}
+
+
+/**
   Checks if possible to do prune partitions on insert.
 
   @param thd           Thread context
diff --git a/sql/partition_info.h b/sql/partition_info.h
index df7010b..336395a 100644
--- a/sql/partition_info.h
+++ b/sql/partition_info.h
@@ -294,7 +294,8 @@ class partition_info : public Sql_alloc
 
   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()
   {
@@ -378,7 +379,7 @@ class partition_info : public Sql_alloc
                                        uint start_no);
   char *create_default_subpartition_name(uint subpart_no,
                                          const char *part_name);
-  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);
   bool is_field_in_part_expr(List<Item> &fields);
   bool is_full_part_expr_in_fields(List<Item> &fields);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 9c56b7d..2f9ec3e 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2533,6 +2533,12 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
   {
     DBUG_ASSERT(table->file != NULL);
     MYSQL_REBIND_TABLE(table->file);
+    if (table->part_info)
+    {
+      /* Set all [named] partitions as used. */
+      if (table->file->change_partitions_to_open(table_list->partition_names))
+        DBUG_RETURN(true);
+    }
   }
   else
   {
@@ -2549,7 +2555,8 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
                                          HA_TRY_READ_ONLY),
                                  (READ_KEYINFO | COMPUTE_TYPES |
                                   EXTRA_RECORD),
-                                 thd->open_options, table, FALSE);
+                                 thd->open_options, table, FALSE,
+                                 table_list->partition_names);
 
     if (error)
     {
@@ -2598,9 +2605,11 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx)
 #ifdef WITH_PARTITION_STORAGE_ENGINE
   if (table->part_info)
   {
+#ifdef CODE_TO_REMOVE
     /* Set all [named] partitions as used. */
     if (table->part_info->set_partition_bitmaps(table_list))
       DBUG_RETURN(true);
+#endif /*CODE_TO_REMOVE*/
   }
   else if (table_list->partition_names)
   {
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index 9e67a21..4a2875c 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -823,8 +823,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))
diff --git a/sql/table.cc b/sql/table.cc
index a1e9ebf..3c29efc 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -2620,7 +2620,7 @@ bool unpack_vcol_info_from_frm(THD *thd,
 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;
@@ -2963,7 +2963,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
 
     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, partitions_to_open);
     if (ha_err)
     {
       share->open_errno= ha_err;
diff --git a/sql/table.h b/sql/table.h
index 876f496..e0cdadf 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -2637,7 +2637,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 unpack_vcol_info_from_frm(THD *thd, MEM_ROOT *mem_root,
                                TABLE *table, Field *field,
                                LEX_STRING *vcol_expr, bool *error_reported);


More information about the commits mailing list