From: Ingo Struewing Date: January 18 2008 9:34am Subject: bk commit into 6.0 tree (istruewing:1.2779) WL#4144 List-Archive: http://lists.mysql.com/commits/41061 Message-Id: Below is the list of changes that have just been committed into a local 6.0 repository of istruewing. When istruewing does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet@stripped, 2008-01-18 10:34:02+01:00, istruewing@stripped +5 -0 WL#4144 - Lock MERGE engine children Step #3: Moved all MERGE specific members from TABLE to ha_myisammrg. Moved members from TABLE to ha_myisammrg. Renamed some mebers. Fixed comments. sql/sql_base.cc@stripped, 2008-01-18 10:34:00+01:00, istruewing@stripped +4 -2 WL#4144 - Lock MERGE engine children Moved is_children_attached() method from TABLE to ha_myisammrg. sql/table.cc@stripped, 2008-01-18 10:34:00+01:00, istruewing@stripped +0 -14 WL#4144 - Lock MERGE engine children Moved is_children_attached() method from TABLE to ha_myisammrg. sql/table.h@stripped, 2008-01-18 10:34:00+01:00, istruewing@stripped +0 -6 WL#4144 - Lock MERGE engine children Moved all MERGE specific members from TABLE to ha_myisammrg. storage/myisammrg/ha_myisammrg.cc@stripped, 2008-01-18 10:34:00+01:00, istruewing@stripped +163 -143 WL#4144 - Lock MERGE engine children Moved all MERGE specific members from TABLE to ha_myisammrg. Renamed children list pointers. Added initialization and free for the children list mem_root. Fixed comments. storage/myisammrg/ha_myisammrg.h@stripped, 2008-01-18 10:34:00+01:00, istruewing@stripped +3 -0 WL#4144 - Lock MERGE engine children Moved all MERGE specific members from TABLE to ha_myisammrg. Renamed children list pointers. Added a mem_root for the children list. diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc --- a/sql/sql_base.cc 2008-01-17 15:22:37 +01:00 +++ b/sql/sql_base.cc 2008-01-18 10:34:00 +01:00 @@ -1982,7 +1982,8 @@ bool rename_temporary_table(THD* thd, TA static void relink_unused(TABLE *table) { /* Assert that MERGE children are not attached in unused_tables. */ - DBUG_ASSERT(!table->is_children_attached()); + DBUG_ASSERT(!table->db_stat || !table->file || + !table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN)); if (table != unused_tables) { @@ -2821,7 +2822,8 @@ TABLE *open_table(THD *thd, TABLE_LIST * table->next->prev=table->prev; table->in_use= thd; /* Assert that MERGE children are not attached in unused_tables. */ - DBUG_ASSERT(!table->is_children_attached()); + DBUG_ASSERT(!table->db_stat || !table->file || + !table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN)); } else { diff -Nrup a/sql/table.cc b/sql/table.cc --- a/sql/table.cc 2008-01-17 15:22:37 +01:00 +++ b/sql/table.cc 2008-01-18 10:34:00 +01:00 @@ -4583,20 +4583,6 @@ void st_table::mark_columns_needed_for_i } -/** - Check if this is a MERGE table with attached children. - - @return status - @retval TRUE children are attached - @retval FALSE children are not attached -*/ - -bool st_table::is_children_attached(void) -{ - /* Must not call extra() on closed table. */ - return(db_stat && file && file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN)); -} - /* Cleanup this table for re-execution. diff -Nrup a/sql/table.h b/sql/table.h --- a/sql/table.h 2008-01-17 15:22:37 +01:00 +++ b/sql/table.h 2008-01-18 10:34:00 +01:00 @@ -463,10 +463,6 @@ struct st_table { #endif struct st_table *next, *prev; - /* For the below MERGE related members see top comment in ha_myisammrg.cc */ - TABLE_LIST *child_l; /* Set in MERGE parent. List of children */ - TABLE_LIST **child_last_l; /* Set in MERGE parent. End of list */ - THD *in_use; /* Which thread uses this */ Field **field; /* Pointer to fields */ @@ -685,8 +681,6 @@ struct st_table { */ inline bool needs_reopen_or_name_lock() { return s->version != refresh_version; } - /* Check if this is a MERGE table with attached children. */ - bool is_children_attached(void); }; enum enum_schema_table_state diff -Nrup a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc --- a/storage/myisammrg/ha_myisammrg.cc 2008-01-17 15:22:37 +01:00 +++ b/storage/myisammrg/ha_myisammrg.cc 2008-01-18 10:34:00 +01:00 @@ -33,40 +33,29 @@ and hence through open_tables(). When the parent appears in the list of tables to open, the initial open of the handler does nothing but read the meta file and collect a list of TABLE_LIST objects for the - children. This list is attached to the parent TABLE object as - TABLE::child_l. The end of the children list is saved in - TABLE::child_last_l. - - Back in open_tables(), add_children_list() is called. It updates - each list member with the lock type and a back pointer to the parent - TABLE_LIST object TABLE_LIST::parent_l. The list is then inserted in - the list of tables to open, right behind the parent. Consequently, - open_tables() opens the children, one after the other. The TABLE - references of the TABLE_LIST objects are implicitly set to the open - tables. The children are opened as independent MyISAM tables, right as - if they are used by the SQL statement. - - TABLE_LIST::parent_l is required to find the parent 1. when the last - child has been opened and children are to be attached, and 2. when an - error happens during child open and the child list must be removed - from the queuery list. In these cases the current child does not have - TABLE::parent set or does not have a TABLE at all respectively. - - When the last child is open, attach_merge_children() is called. It - removes the list of children from the open list. Then the children are - "attached" to the parent. All required references between parent and + children. This list is attached to the handler object as + ha_myisammrg::children_l. The end of the children list is saved in + ha_myisammrg::children_last_l. + + Back in open_tables(), handler::extra(HA_EXTRA_ADD_CHILDREN_LIST) is + called. It updates each list member with the lock type and a back + pointer to the parent TABLE_LIST object TABLE_LIST::parent_l. The list + is then inserted in the list of tables to open, right behind the + parent. Consequently, open_tables() opens the children, one after the + other. The TABLE references of the TABLE_LIST objects are implicitly + set to the open tables by open_table(). The children are opened as + independent MyISAM tables, right as if they are used by the SQL + statement. + + When all tables from the statement query list are open, + handler::extra(HA_EXTRA_ATTACH_CHILDREN) is called. It "attaches" the + children to the parent. All required references between parent and children are set up. The MERGE storage engine sets up an array with references to the low-level MyISAM table objects (MI_INFO). It remembers the state of the table in MYRG_INFO::children_attached. - Every child TABLE::parent references the parent TABLE object. That way - TABLE objects belonging to a MERGE table can be identified. - TABLE::parent is required because the parent and child TABLE objects - can live longer than the parent TABLE_LIST object. So the path - child->pos_in_table_list->parent_l->table can be broken. - If necessary, the compatibility of parent and children is checked. This check is necessary when any of the objects are reopend. This is detected by comparing the current table def version against the @@ -80,14 +69,20 @@ myisammrg_attach_children_callback() sets it ot TRUE if a table def version mismatches the remembered child def version. - Finally the parent TABLE::children_attached is set. + The children chain remains in the statement query list until the table + is closed or the children are detached. This is done so that the + children are locked by lock_tables(). + + At statement end the children are detached. At the next statement + begin the open-add-attach sequence repeats. There is no exception for + LOCK TABLES. The fresh establishment of the parent-child relationship + before every statement catches numerous cases of ALTER/FLUSH/DROP/etc + of parent or children during LOCK TABLES. --- On parent open the storage engine structures are allocated and initialized. They stay with the open table until its final close. - - */ #ifdef USE_PRAGMA_IMPLEMENTATION @@ -117,7 +112,10 @@ static handler *myisammrg_create_handler ha_myisammrg::ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg) :handler(hton, table_arg), file(0) -{} +{ + init_sql_alloc(&children_mem_root, max(4 * sizeof(TABLE_LIST), FN_REFLEN) + + ALLOC_ROOT_MIN_BLOCK_SIZE, 0); +} /** @@ -125,7 +123,9 @@ ha_myisammrg::ha_myisammrg(handlerton *h */ ha_myisammrg::~ha_myisammrg(void) -{} +{ + free_root(&children_mem_root, MYF(0)); +} static const char *ha_myisammrg_exts[] = { @@ -176,45 +176,48 @@ const char *ha_myisammrg::index_type(uin /** - @brief Callback function for open of a MERGE parent table. - - @detail This function adds a TABLE_LIST object for a MERGE child table - to a list of tables of the parent TABLE object. It is called for - each child table. - - The list of child TABLE_LIST objects is kept in the TABLE object of - the parent for the whole life time of the MERGE table. It is - inserted in the statement list behind the MERGE parent TABLE_LIST - object when the MERGE table is opened. It is removed from the - statement list after the last child is opened. - - All memeory used for the child TABLE_LIST objects and the strings - referred by it are taken from the parent TABLE::mem_root. Thus they - are all freed implicitly at the final close of the table. - - TABLE::child_l -> TABLE_LIST::next_global -> TABLE_LIST::next_global - # # ^ # ^ - # # | # | - # # +--------- TABLE_LIST::prev_global - # # | - # |<--- TABLE_LIST::prev_global | - # | - TABLE::child_last_l -----------------------------------------+ + Callback function for open of a MERGE parent table. @param[in] callback_param data pointer as given to myrg_parent_open() + this is used to pass the handler handle @param[in] filename file name of MyISAM table without extension. @return status @retval 0 OK @retval != 0 Error + + @detail + + This function adds a TABLE_LIST object for a MERGE child table to a + list of tables in the parent handler object. It is called for each + child table. + + The list of child TABLE_LIST objects is kept in the handler object + of the parent for the whole life time of the MERGE table. It is + inserted in the statement query list behind the MERGE parent + TABLE_LIST object when the MERGE table is opened. It is removed from + the statement query list at end of statement or at children detach. + + All memory used for the child TABLE_LIST objects and the strings + referred by it are taken from the parent + ha_myisammrg::children_mem_root. Thus they are all freed implicitly at + the final close of the table. + + children_l -> TABLE_LIST::next_global -> TABLE_LIST::next_global + # # ^ # ^ + # # | # | + # # +--------- TABLE_LIST::prev_global + # # | + # |<--- TABLE_LIST::prev_global | + # | + children_last_l -----------------------------------------+ */ static int myisammrg_parent_open_callback(void *callback_param, const char *filename) { - ha_myisammrg *ha_myrg; - TABLE *parent; + ha_myisammrg *ha_myrg= (ha_myisammrg*) callback_param; TABLE_LIST *child_l; const char *db; const char *table_name; @@ -240,11 +243,8 @@ static int myisammrg_parent_open_callbac dirlen-= db - dir_path; /* This is now the length of 'db'. */ DBUG_PRINT("myrg", ("open: '%s'.'%s'", db, table_name)); - ha_myrg= (ha_myisammrg*) callback_param; - parent= ha_myrg->table_ptr(); - /* Get a TABLE_LIST object. */ - if (!(child_l= (TABLE_LIST*) alloc_root(&parent->mem_root, + if (!(child_l= (TABLE_LIST*) alloc_root(&ha_myrg->children_mem_root, sizeof(TABLE_LIST)))) { /* purecov: begin inspected */ @@ -256,10 +256,10 @@ static int myisammrg_parent_open_callbac /* Set database (schema) name. */ child_l->db_length= dirlen; - child_l->db= strmake_root(&parent->mem_root, db, dirlen); + child_l->db= strmake_root(&ha_myrg->children_mem_root, db, dirlen); /* Set table name. */ child_l->table_name_length= strlen(table_name); - child_l->table_name= strmake_root(&parent->mem_root, table_name, + child_l->table_name= strmake_root(&ha_myrg->children_mem_root, table_name, child_l->table_name_length); /* Convert to lowercase if required. */ if (lower_case_table_names && child_l->table_name_length) @@ -271,26 +271,23 @@ static int myisammrg_parent_open_callbac /* Initialize table map to 'undefined'. */ child_l->init_child_def_version(); - /* Link TABLE_LIST object into the parent list. */ - if (parent->child_last_l) - child_l->prev_global= parent->child_last_l; + /* Link TABLE_LIST object into the children list. */ + if (ha_myrg->children_last_l) + child_l->prev_global= ha_myrg->children_last_l; else { - /* Initialize parent->child_last_l when handling first child. */ - parent->child_last_l= &parent->child_l; + /* Initialize ha_myrg->children_last_l when handling first child. */ + ha_myrg->children_last_l= &ha_myrg->children_l; } - *parent->child_last_l= child_l; - parent->child_last_l= &child_l->next_global; + *ha_myrg->children_last_l= child_l; + ha_myrg->children_last_l= &child_l->next_global; DBUG_RETURN(0); } /** - @brief Open a MERGE parent table, not its children. - - @detail This function initializes the MERGE storage engine structures - and adds a child list of TABLE_LIST to the parent TABLE. + Open a MERGE parent table, but not its children. @param[in] name MERGE table path name @param[in] mode read/write mode, unused @@ -299,6 +296,10 @@ static int myisammrg_parent_open_callbac @return status @retval 0 OK @retval -1 Error, my_errno gives reason + + @detail + This function initializes the MERGE storage engine structures + and adds a child list of TABLE_LIST to the parent handler. */ int ha_myisammrg::open(const char *name, int mode __attribute__((unused)), @@ -308,11 +309,28 @@ int ha_myisammrg::open(const char *name, DBUG_PRINT("myrg", ("name: '%s' table: 0x%lx", name, (long) table)); DBUG_PRINT("myrg", ("test_if_locked: %u", test_if_locked)); + /* Must not be used when table is open. */ + DBUG_ASSERT(!this->file); + /* Save for later use. */ this->test_if_locked= test_if_locked; - /* retrieve children table list. */ + /* In case this handler was open and closed before, free old data. */ + free_root(&this->children_mem_root, MYF(MY_MARK_BLOCKS_FREE)); + + /* + Initialize variables that are used, modified, and/or set by + myisammrg_parent_open_callback(). + 'children_l' is the head of the children chain. + 'children_last_l' points to the end of the children chain. + 'my_errno' is set by myisammrg_parent_open_callback() in + case of an error. + */ + children_l= NULL; + children_last_l= NULL; my_errno= 0; + + /* retrieve children table list. */ if (!(file= myrg_parent_open(name, myisammrg_parent_open_callback, this))) { DBUG_PRINT("error", ("my_errno %d", my_errno)); @@ -351,13 +369,16 @@ int ha_myisammrg::add_children_list(void /* Ignore this for empty MERGE tables (UNION=()). */ if (!this->file->tables) + { + DBUG_PRINT("myrg", ("empty merge table union")); goto end; + } /* Must not call this with attached children. */ DBUG_ASSERT(!this->file->children_attached); /* Must not call this with children list in place. */ - DBUG_ASSERT(parent_l->next_global != this->table->child_l); + DBUG_ASSERT(parent_l->next_global != this->children_l); /* Prevent inclusion of another MERGE table, which could make infinite @@ -369,37 +390,32 @@ int ha_myisammrg::add_children_list(void DBUG_RETURN(1); } - /* Fix children.*/ - for (child_l= this->table->child_l; ; child_l= child_l->next_global) + /* Fix children. */ + DBUG_ASSERT(this->children_l); + for (child_l= this->children_l; ; child_l= child_l->next_global) { - /* - Note: child_l->table may still be set if this parent was taken - from the unused_tables chain. Ignore this fact here. The - reference will be replaced by the handler in - ::extra(HA_EXTRA_ATTACH_CHILDREN). - */ DBUG_ASSERT(!child_l->table); /* Set lock type. */ child_l->lock_type= parent_l->lock_type; - /* Set parent reference. */ + /* Set parent reference. Used to detect MERGE in children list. */ child_l->parent_l= parent_l; /* Copy select_lex. Used in unique_table() at least. */ child_l->select_lex= parent_l->select_lex; /* Break when this was the last child. */ - if (&child_l->next_global == this->table->child_last_l) + if (&child_l->next_global == this->children_last_l) break; } /* Insert children into the table list. */ if (parent_l->next_global) - parent_l->next_global->prev_global= this->table->child_last_l; - *this->table->child_last_l= parent_l->next_global; - parent_l->next_global= this->table->child_l; - this->table->child_l->prev_global= &parent_l->next_global; + parent_l->next_global->prev_global= this->children_last_l; + *this->children_last_l= parent_l->next_global; + parent_l->next_global= this->children_l; + this->children_l->prev_global= &parent_l->next_global; end: DBUG_RETURN(0); @@ -407,32 +423,31 @@ int ha_myisammrg::add_children_list(void /** - @brief Callback function for attaching a MERGE child table. + Callback function for attaching a MERGE child table. - @detail This function retrieves the MyISAM table handle from the - next child table. It is called for each child table. - - @param[in] callback_param data pointer as given to - myrg_attach_children() + @param[in] callback_param data pointer as given to myrg_attach_children() + this is used to pass the handler handle @return pointer to open MyISAM table structure @retval !=NULL OK, returning pointer @retval NULL, my_errno == 0 Ok, no more child tables @retval NULL, my_errno != 0 error + + @detail + This function retrieves the MyISAM table handle from the + next child table. It is called for each child table. */ static MI_INFO *myisammrg_attach_children_callback(void *callback_param) { - ha_myisammrg *ha_myrg; - TABLE *parent; + ha_myisammrg *ha_myrg= (ha_myisammrg*) callback_param; + TABLE *parent= ha_myrg->table_ptr(); TABLE *child; TABLE_LIST *child_l; MI_INFO *myisam; DBUG_ENTER("myisammrg_attach_children_callback"); my_errno= 0; - ha_myrg= (ha_myisammrg*) callback_param; - parent= ha_myrg->table_ptr(); /* Get child list item. */ child_l= ha_myrg->next_child_attach; @@ -448,7 +463,7 @@ static MI_INFO *myisammrg_attach_childre Prepare for next child. Used as child_l in next call to this function. We cannot rely on a NULL-terminated chain. */ - if (&child_l->next_global == parent->child_last_l) + if (&child_l->next_global == ha_myrg->children_last_l) { DBUG_PRINT("myrg", ("attaching last child")); ha_myrg->next_child_attach= NULL; @@ -505,22 +520,24 @@ static MI_INFO *myisammrg_attach_childre /** - @brief Attach children to a MERGE table. + Attach children to a MERGE table. + + @return status + @retval 0 OK + @retval != 0 Error, my_errno gives reason - @detail Let the storage engine attach its children through a callback + @detail + Let the storage engine attach its children through a callback function. Check table definitions for consistency. - @note Special thd->open_options may be in effect. We can make use of + @note + Special thd->open_options may be in effect. We can make use of them in attach. I.e. we use HA_OPEN_FOR_REPAIR to report the names of mismatching child tables. We cannot transport these options in ha_myisammrg::test_if_locked because they may change after the parent is opened. The parent is kept open in the table cache over multiple statements and can be used by other threads. Open options can change over time. - - @return status - @retval 0 OK - @retval != 0 Error, my_errno gives reason */ int ha_myisammrg::attach_children(void) @@ -536,23 +553,25 @@ int ha_myisammrg::attach_children(void) table->s->table_name.str, (long) table)); DBUG_PRINT("myrg", ("test_if_locked: %u", this->test_if_locked)); + /* Must call this with open table. */ + DBUG_ASSERT(this->file); + /* A MERGE table with no children (empty union) is always seen as attached internally. */ - DBUG_ASSERT(this->file); - DBUG_PRINT("myrg", ("child tables: %u", this->file->tables)); if (!this->file->tables) { - DBUG_PRINT("myrg", ("empty merge table")); + DBUG_PRINT("myrg", ("empty merge table union")); goto end; } + DBUG_PRINT("myrg", ("child tables: %u", this->file->tables)); /* Must not call this with attached children. */ DBUG_ASSERT(!this->file->children_attached); + /* Must call this with children list in place. */ - DBUG_ASSERT(this->table->pos_in_table_list->next_global == - this->table->child_l); + DBUG_ASSERT(this->table->pos_in_table_list->next_global == this->children_l); /* Initialize variables that are used, modified, and/or set by @@ -566,7 +585,7 @@ int ha_myisammrg::attach_children(void) 'my_errno' is set by myisammrg_attach_children_callback() in case of an error. */ - next_child_attach= table->child_l; + next_child_attach= this->children_l; need_compat_check= FALSE; my_errno= 0; @@ -641,12 +660,13 @@ int ha_myisammrg::attach_children(void) goto err; /* All checks passed so far. Now update child def version. */ - for (child_l= table->child_l; ; child_l= child_l->next_global) + DBUG_ASSERT(this->children_l); + for (child_l= this->children_l; ; child_l= child_l->next_global) { child_l->set_child_def_version( child_l->table->s->get_table_def_version()); - if (&child_l->next_global == table->child_last_l) + if (&child_l->next_global == this->children_last_l) break; } } @@ -672,15 +692,16 @@ err: /** - @brief Detach all children from a MERGE table. - - @note Detach must not touch the child TABLE objects in any way. - They may have been closed at ths point already. - All references to the children should be removed. + Detach all children from a MERGE table. @return status @retval 0 OK @retval != 0 Error, my_errno gives reason + + @note + Detach must not touch the child TABLE objects in any way. + They may have been closed at ths point already. + All references to the children should be removed. */ int ha_myisammrg::detach_children(void) @@ -688,21 +709,19 @@ int ha_myisammrg::detach_children(void) TABLE_LIST *child_l; DBUG_ENTER("ha_myisammrg::detach_children"); - /* - At end of ALTER TABLE this is called via close_thread_tables() for a - previously closed table. A MERGE table with no children (empty - union) cannot be detached. - */ + /* Must call this with open table. */ DBUG_ASSERT(this->file); + + /* A MERGE table with no children (empty union) cannot be detached. */ if (!this->file->tables) { - DBUG_PRINT("myrg", ("empty merge table")); + DBUG_PRINT("myrg", ("empty merge table union")); goto end; } /* Clear TABLE references. */ - DBUG_ASSERT(this->table->child_l); - for (child_l= this->table->child_l; ; child_l= child_l->next_global) + DBUG_ASSERT(this->children_l); + for (child_l= this->children_l; ; child_l= child_l->next_global) { /* Do not DBUG_ASSERT(child_l->table); open_tables might be @@ -713,7 +732,7 @@ int ha_myisammrg::detach_children(void) child_l->table= NULL; /* Break when this was the last child. */ - if (&child_l->next_global == this->table->child_last_l) + if (&child_l->next_global == this->children_last_l) break; } @@ -721,14 +740,14 @@ int ha_myisammrg::detach_children(void) Remove children from the table list. This won't fail if called twice. The list is terminated after removal. */ - if (table->child_l->prev_global) - *table->child_l->prev_global= *table->child_last_l; - if (*table->child_last_l) - (*table->child_last_l)->prev_global= table->child_l->prev_global; - - /* Terminate child list. So it cannot be tried to removed again. */ - *table->child_last_l= NULL; - table->child_l->prev_global= NULL; + if (this->children_l->prev_global) + *this->children_l->prev_global= *this->children_last_l; + if (*this->children_last_l) + (*this->children_last_l)->prev_global= this->children_l->prev_global; + + /* Terminate child list. So it cannot be tried to remove again. */ + *this->children_last_l= NULL; + this->children_l->prev_global= NULL; if (!this->file->children_attached) { @@ -750,13 +769,14 @@ int ha_myisammrg::detach_children(void) /** - @brief Close a MERGE parent table, not its children. - - @note The children are expected to be closed separately by the caller. + Close a MERGE parent table, but not its children. @return status @retval 0 OK @retval != 0 Error, my_errno gives reason + + @note + The children are expected to be closed separately by the caller. */ int ha_myisammrg::close(void) diff -Nrup a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h --- a/storage/myisammrg/ha_myisammrg.h 2008-01-17 15:22:38 +01:00 +++ b/storage/myisammrg/ha_myisammrg.h 2008-01-18 10:34:00 +01:00 @@ -27,6 +27,9 @@ class ha_myisammrg: public handler MYRG_INFO *file; public: + MEM_ROOT children_mem_root; /* mem root for children list */ + TABLE_LIST *children_l; /* children list */ + TABLE_LIST **children_last_l; /* children list end */ TABLE_LIST *next_child_attach; /* next child to attach */ uint test_if_locked; /* flags from ::open() */ bool need_compat_check; /* if need compatibility check */