[Commits] d970306a53e9d0e4877446ad50be13c3c962ecf4 Initial patch (non-functional) for MDEV-11050: Reuse temporary tables created for materialized CTE tables.

Igor Babaev igor at askmonty.org
Wed Oct 19 01:29:52 EEST 2016


commit d970306a53e9d0e4877446ad50be13c3c962ecf4
Author: Igor Babaev <igor at askmonty.org>
Commit: Igor Babaev <igor at askmonty.org>

    Initial patch (non-functional) for MDEV-11050:
    Reuse temporary tables created for materialized CTE tables.
---
 sql/handler.cc     |    8 ++++--
 sql/sql_cte.h      |    2 +
 sql/sql_derived.cc |   45 ++++++++++++++++++++++++++-------------
 sql/sql_select.cc  |   28 +++++++++++++++--------
 sql/table.cc       |   59 ++++++++++++++++++++++++++++++++++++++++++---------
 sql/table.h        |    8 ++++++-
 6 files changed, 110 insertions(+), 40 deletions(-)

diff --git a/sql/handler.cc b/sql/handler.cc
index d7481f8..5714b80 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -2495,7 +2495,9 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
   DBUG_ASSERT(table->s == table_share);
   DBUG_ASSERT(m_lock_type == F_UNLCK);
   DBUG_PRINT("info", ("old m_lock_type: %d F_UNLCK %d", m_lock_type, F_UNLCK));
-  DBUG_ASSERT(alloc_root_inited(&table->mem_root));
+  MEM_ROOT *mem_root= (test_if_locked & HA_OPEN_TMP_TABLE) ?
+    &table->s->mem_root : &table->mem_root;
+  DBUG_ASSERT(alloc_root_inited(mem_root));
 
   if ((error=open(name,mode,test_if_locked)))
   {
@@ -2530,8 +2532,8 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
     (void) extra(HA_EXTRA_NO_READCHECK);	// Not needed in SQL
 
     /* ref is already allocated for us if we're called from handler::clone() */
-    if (!ref && !(ref= (uchar*) alloc_root(&table->mem_root, 
-                                          ALIGN_SIZE(ref_length)*2)))
+    if (!ref && !(ref= (uchar*) alloc_root(mem_root, 
+                                           ALIGN_SIZE(ref_length)*2)))
     {
       ha_close();
       error=HA_ERR_OUT_OF_MEM;
diff --git a/sql/sql_cte.h b/sql/sql_cte.h
index 27d5923..6cc2e08 100644
--- a/sql/sql_cte.h
+++ b/sql/sql_cte.h
@@ -119,6 +119,8 @@ class With_element : public Sql_alloc
   */
   select_union_recursive *rec_result;
 
+  List<TABLE> tmp_tables;
+
   With_element(LEX_STRING *name,
                List <LEX_STRING> list,
                st_select_lex_unit *unit)
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 0b67b95..c63a839 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -746,22 +746,37 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
     !unit->union_distinct->next_select() (i.e. it is union and last distinct
     SELECT is last SELECT of UNION).
   */
-  thd->create_tmp_table_for_derived= TRUE;
-  if (!(derived->table) &&
-      derived->derived_result->create_result_table(thd, &unit->types, FALSE,
-                                                   (first_select->options |
-                                                   thd->variables.option_bits |
-                                                   TMP_TABLE_ALL_COLUMNS),
-                                                   derived->alias,
-                                                   FALSE, FALSE, FALSE))
-  { 
-    thd->create_tmp_table_for_derived= FALSE;
-    goto exit;
-  }
-  thd->create_tmp_table_for_derived= FALSE;
-
   if (!derived->table)
-    derived->table= derived->derived_result->table;
+  {
+    if (derived->with && derived->with->tmp_tables.elements > 0)
+    {
+      TABLE *cloned_table= derived->with->tmp_tables.head(); 
+      derived->table=
+        cloned_table->create_table_clone_for_tmp_table(thd,derived->alias);
+    }
+    else
+    {
+      thd->create_tmp_table_for_derived= TRUE;
+      if (!derived->derived_result->create_result_table(
+                                                 thd, &unit->types, FALSE,
+                                                 (first_select->options |
+                                                  thd->variables.option_bits |
+                                                  TMP_TABLE_ALL_COLUMNS),
+                                                 derived->alias,
+                                                 FALSE, FALSE, FALSE))
+      {
+        TABLE *created_table= derived->derived_result->table;
+        if (!derived->with ||
+            !derived->with->tmp_tables.push_back(created_table))
+          derived->table= created_table;
+      }    
+      thd->create_tmp_table_for_derived= FALSE;
+    }
+    if (!derived->table)
+      goto exit;
+    if (derived->with)
+      derived->table->clones= &derived->with->tmp_tables;
+  }    
   DBUG_ASSERT(derived->table);
   if (derived->is_derived() && derived->is_merged_derived())
     first_select->mark_as_belong_to_derived(derived);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 1f79010..e7cd904 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -16310,10 +16310,6 @@ static bool equal(Item *i1, Item *i2, Field *f2)
   bzero((char*) default_field, sizeof(Field*) * (field_count));
   bzero((char*) from_field,sizeof(Field*)*field_count);
 
-  table->mem_root= own_root;
-  mem_root_save= thd->mem_root;
-  thd->mem_root= &table->mem_root;
-
   table->field=reg_field;
   table->alias.set(table_alias, strlen(table_alias), table_alias_charset);
 
@@ -16330,7 +16326,19 @@ static bool equal(Item *i1, Item *i2, Field *f2)
   table->no_rows_with_nulls= param->force_not_null_cols;
 
   table->s= share;
-  init_tmp_table_share(thd, share, "", 0, tmpname, tmpname);
+  init_tmp_table_share(thd, share, "", 0, tmpname, tmpname, &own_root);
+
+  /*
+    We will use TABLE_SHARE's MEM_ROOT for all allocations, so TABLE's
+    MEM_ROOT remains uninitialized.
+    TABLE_SHARE's MEM_ROOT is a copy of own_root, upon error free_tmp_table()
+    will free it.
+  */
+  mem_root_save= thd->mem_root;
+  thd->mem_root= &share->mem_root;
+  memset(&own_root, 0, sizeof(own_root)); // to be sure it's not used anymore
+
+  share->field= table->field;
   share->blob_field= blob_field;
   share->table_charset= param->table_charset;
   share->primary_key= MAX_KEY;               // Indicate no primary key
@@ -16406,7 +16414,7 @@ static bool equal(Item *i1, Item *i2, Field *f2)
           }
           thd->mem_root= mem_root_save;
           arg= sum_item->set_arg(i, thd, new (thd->mem_root) Item_temptable_field(thd, new_field));
-          thd->mem_root= &table->mem_root;
+          thd->mem_root= &share->mem_root;
           if (param->force_not_null_cols)
 	  {
             new_field->flags|= NOT_NULL_FLAG;
@@ -16569,7 +16577,7 @@ static bool equal(Item *i1, Item *i2, Field *f2)
   else
   {
     share->db_plugin= ha_lock_engine(0, heap_hton);
-    table->file= get_new_handler(share, &table->mem_root,
+    table->file= get_new_handler(share, &share->mem_root,
                                  share->db_type());
   }
   if (!table->file)
@@ -16612,7 +16620,7 @@ static bool equal(Item *i1, Item *i2, Field *f2)
     uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1);
     share->rec_buff_length= alloc_length;
     if (!(table->record[0]= (uchar*)
-                            alloc_root(&table->mem_root, alloc_length*3)))
+                            alloc_root(&share->mem_root, alloc_length*3)))
       goto err;
     table->record[1]= table->record[0]+alloc_length;
     share->default_values= table->record[1]+alloc_length;
@@ -16859,7 +16867,7 @@ static bool equal(Item *i1, Item *i2, Field *f2)
     table->distinct= 1;
     share->keys= 1;
     if (!(key_part_info= (KEY_PART_INFO*)
-          alloc_root(&table->mem_root,
+          alloc_root(&share->mem_root,
                      keyinfo->user_defined_key_parts * sizeof(KEY_PART_INFO))))
       goto err;
     bzero((void*) key_part_info, keyinfo->user_defined_key_parts * sizeof(KEY_PART_INFO));
@@ -16886,7 +16894,7 @@ static bool equal(Item *i1, Item *i2, Field *f2)
        see get_delayed_table_estimates()).
     */
     size_t rpk_size= keyinfo->user_defined_key_parts * sizeof(keyinfo->rec_per_key[0]);
-    if (!(keyinfo->rec_per_key= (ulong*) alloc_root(&table->mem_root, 
+    if (!(keyinfo->rec_per_key= (ulong*) alloc_root(&share->mem_root, 
                                                     rpk_size)))
       goto err;
     bzero(keyinfo->rec_per_key, rpk_size);
diff --git a/sql/table.cc b/sql/table.cc
index 4c68bcb..15b07d6 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -360,6 +360,8 @@ TABLE_CATEGORY get_table_category(const LEX_STRING *db, const LEX_STRING *name)
     key_length	Length of key
     table_name	Table name
     path	Path to file (possible in lower case) without .frm
+    @param mem_root  MEM_ROOT to copy and give to the TABLE_SHARE;
+                     if NULL a new one is initialized.
 
   NOTES
     This is different from alloc_table_share() because temporary tables
@@ -373,18 +375,28 @@ TABLE_CATEGORY get_table_category(const LEX_STRING *db, const LEX_STRING *name)
 
 void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,
                           uint key_length, const char *table_name,
-                          const char *path)
+                          const char *path, MEM_ROOT *mem_root)
 {
   DBUG_ENTER("init_tmp_table_share");
   DBUG_PRINT("enter", ("table: '%s'.'%s'", key, table_name));
 
   bzero((char*) share, sizeof(*share));
-  /*
-    This can't be MY_THREAD_SPECIFIC for slaves as they are freed
-    during cleanup() from Relay_log_info::close_temporary_tables()
-  */
-  init_sql_alloc(&share->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, 
-                 MYF(thd->slave_thread ? 0 : MY_THREAD_SPECIFIC));
+
+  if (mem_root)
+  {
+    /* This invokes (the synthesized) st_mem_root &operator=(const st_mem_root&) */
+    share->mem_root= *mem_root;
+  }
+  else
+  {
+    /*
+      This can't be MY_THREAD_SPECIFIC for slaves as they are freed
+      during cleanup() from Relay_log_info::close_temporary_tables()
+    */
+    init_sql_alloc(&share->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, 
+                   MYF(thd->slave_thread ? 0 : MY_THREAD_SPECIFIC));
+  }
+
   share->table_category=         TABLE_CATEGORY_TEMPORARY;
   share->tmp_table=              INTERNAL_TMP_TABLE;
   share->db.str=                 (char*) key;
@@ -6627,6 +6639,31 @@ void TABLE::mark_default_fields_for_write(bool is_insert)
 }
 
 
+TABLE *TABLE::create_table_clone_for_tmp_table(THD *thd,
+                                               const char *alias)
+{
+  /* Allocate clone on the memory root of the TABLE_SHARE */
+  TABLE *t= static_cast<TABLE *>(alloc_root(&s->mem_root, sizeof(TABLE)));
+  if (!t || clones->push_back(t))
+    return NULL;
+  /* This function can be called only when s->keys == 0 */
+  DBUG_ASSERT(s->keys == 0);
+  if (open_table_from_share(thd, s, alias, 0,
+                            EXTRA_RECORD | DELAYED_OPEN,
+                            0, t, FALSE))
+    return NULL;
+  DBUG_ASSERT(t->s == s);
+  t->file->change_table_ptr(t, s);
+
+  /* In case this clone is used to fill the materialized table: */
+  bitmap_set_all(t->write_set);
+  t->reginfo.lock_type= TL_WRITE;
+  t->copy_blobs= 1;
+
+  return t;
+}
+
+
 /**
   @brief
   Allocate space for keys
@@ -6643,7 +6680,7 @@ void TABLE::mark_default_fields_for_write(bool is_insert)
 
 bool TABLE::alloc_keys(uint key_count)
 {
-  key_info= (KEY*) alloc_root(&mem_root, sizeof(KEY)*(s->keys+key_count));
+  key_info= (KEY*) alloc_root(&s->mem_root, sizeof(KEY)*(s->keys+key_count));
   if (s->keys)
     memmove(key_info, s->key_info, sizeof(KEY)*s->keys);
   s->key_info= key_info;
@@ -6797,7 +6834,7 @@ bool TABLE::add_tmp_key(uint key, uint key_parts,
 
   bool key_start= TRUE;
   KEY_PART_INFO* key_part_info=
-      (KEY_PART_INFO*) alloc_root(&mem_root, sizeof(KEY_PART_INFO)*key_parts);
+      (KEY_PART_INFO*) alloc_root(&s->mem_root, sizeof(KEY_PART_INFO)*key_parts);
   if (!key_part_info)
     return TRUE;
   keyinfo= key_info + key;
@@ -6812,9 +6849,9 @@ bool TABLE::add_tmp_key(uint key, uint key_parts,
   if (unique)
     keyinfo->flags|= HA_NOSAME;
   sprintf(buf, "key%i", key);
-  if (!(keyinfo->name= strdup_root(&mem_root, buf)))
+  if (!(keyinfo->name= strdup_root(&s->mem_root, buf)))
     return TRUE;
-  keyinfo->rec_per_key= (ulong*) alloc_root(&mem_root,
+  keyinfo->rec_per_key= (ulong*) alloc_root(&s->mem_root,
                                             sizeof(ulong)*key_parts);
   if (!keyinfo->rec_per_key)
     return TRUE;
diff --git a/sql/table.h b/sql/table.h
index bc30b00..84f5061 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1072,6 +1072,8 @@ struct TABLE
   /* Position in thd->locked_table_list under LOCK TABLES */
   TABLE_LIST *pos_in_locked_tables;
 
+  List<TABLE> *clones;
+
   /*
     Not-null for temporary tables only. Non-null values means this table is
     used to compute GROUP BY, it has a unique of GROUP BY columns.
@@ -1358,6 +1360,9 @@ struct TABLE
   inline bool needs_reopen()
   { return !db_stat || m_needs_reopen; }
 
+  TABLE *create_table_clone_for_tmp_table(THD *thd,
+                                          const char *alias);
+
   bool alloc_keys(uint key_count);
   bool check_tmp_key(uint key, uint key_parts,
                      uint (*next_field_no) (uchar *), uchar *arg);
@@ -2643,7 +2648,8 @@ bool fix_session_vcol_expr_for_read(THD *thd, Field *field,
                                const char *key, uint key_length);
 void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,
                           uint key_length,
-                          const char *table_name, const char *path);
+                          const char *table_name, const char *path,
+                          MEM_ROOT *mem_root = NULL);
 void free_table_share(TABLE_SHARE *share);
 enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share,
                                    uint flags = GTS_TABLE);


More information about the commits mailing list