33
33
and hence through open_tables(). When the parent appears in the list
34
34
of tables to open, the initial open of the handler does nothing but
35
35
read the meta file and collect a list of TABLE_LIST objects for the
36
children. This list is attached to the parent TABLE object as
37
TABLE::child_l. The end of the children list is saved in
40
Back in open_tables(), add_merge_table_list() is called. It updates
41
each list member with the lock type and a back pointer to the parent
42
TABLE_LIST object TABLE_LIST::parent_l. The list is then inserted in
43
the list of tables to open, right behind the parent. Consequently,
44
open_tables() opens the children, one after the other. The TABLE
45
references of the TABLE_LIST objects are implicitly set to the open
46
tables. The children are opened as independent MyISAM tables, right as
47
if they are used by the SQL statement.
49
TABLE_LIST::parent_l is required to find the parent 1. when the last
50
child has been opened and children are to be attached, and 2. when an
51
error happens during child open and the child list must be removed
52
from the queuery list. In these cases the current child does not have
53
TABLE::parent set or does not have a TABLE at all respectively.
55
When the last child is open, attach_merge_children() is called. It
56
removes the list of children from the open list. Then the children are
57
"attached" to the parent. All required references between parent and
36
children. This list is attached to the handler object as
37
ha_myisammrg::children_l. The end of the children list is saved in
38
ha_myisammrg::children_last_l.
40
Back in open_tables(), handler::extra(HA_EXTRA_ADD_CHILDREN_LIST) is
41
called. It updates each list member with the lock type and a back
42
pointer to the parent TABLE_LIST object TABLE_LIST::parent_l. The list
43
is then inserted in the list of tables to open, right behind the
44
parent. Consequently, open_tables() opens the children, one after the
45
other. The TABLE references of the TABLE_LIST objects are implicitly
46
set to the open tables by open_table(). The children are opened as
47
independent MyISAM tables, right as if they are used by the SQL
50
When all tables from the statement query list are open,
51
handler::extra(HA_EXTRA_ATTACH_CHILDREN) is called. It "attaches" the
52
children to the parent. All required references between parent and
58
53
children are set up.
60
55
The MERGE storage engine sets up an array with references to the
61
56
low-level MyISAM table objects (MI_INFO). It remembers the state of
62
57
the table in MYRG_INFO::children_attached.
64
Every child TABLE::parent references the parent TABLE object. That way
65
TABLE objects belonging to a MERGE table can be identified.
66
TABLE::parent is required because the parent and child TABLE objects
67
can live longer than the parent TABLE_LIST object. So the path
68
child->pos_in_table_list->parent_l->table can be broken.
70
59
If necessary, the compatibility of parent and children is checked.
71
60
This check is necessary when any of the objects are reopend. This is
72
61
detected by comparing the current table def version against the
179
@brief Callback function for open of a MERGE parent table.
181
@detail This function adds a TABLE_LIST object for a MERGE child table
182
to a list of tables of the parent TABLE object. It is called for
185
The list of child TABLE_LIST objects is kept in the TABLE object of
186
the parent for the whole life time of the MERGE table. It is
187
inserted in the statement list behind the MERGE parent TABLE_LIST
188
object when the MERGE table is opened. It is removed from the
189
statement list after the last child is opened.
191
All memeory used for the child TABLE_LIST objects and the strings
192
referred by it are taken from the parent TABLE::mem_root. Thus they
193
are all freed implicitly at the final close of the table.
195
TABLE::child_l -> TABLE_LIST::next_global -> TABLE_LIST::next_global
198
# # +--------- TABLE_LIST::prev_global
200
# |<--- TABLE_LIST::prev_global |
202
TABLE::child_last_l -----------------------------------------+
181
Callback function for open of a MERGE parent table.
204
183
@param[in] callback_param data pointer as given to myrg_parent_open()
184
this is used to pass the handler handle
205
185
@param[in] filename file name of MyISAM table
206
186
without extension.
210
190
@retval != 0 Error
194
This function adds a TABLE_LIST object for a MERGE child table to a
195
list of tables in the parent handler object. It is called for each
198
The list of child TABLE_LIST objects is kept in the handler object
199
of the parent for the whole life time of the MERGE table. It is
200
inserted in the statement query list behind the MERGE parent
201
TABLE_LIST object when the MERGE table is opened. It is removed from
202
the statement query list at end of statement or at children detach.
204
All memory used for the child TABLE_LIST objects and the strings
205
referred by it are taken from the parent
206
ha_myisammrg::children_mem_root. Thus they are all freed implicitly at
207
the final close of the table.
209
children_l -> TABLE_LIST::next_global -> TABLE_LIST::next_global
212
# # +--------- TABLE_LIST::prev_global
214
# |<--- TABLE_LIST::prev_global |
216
children_last_l -----------------------------------------+
213
219
static int myisammrg_parent_open_callback(void *callback_param,
214
220
const char *filename)
216
ha_myisammrg *ha_myrg;
222
ha_myisammrg *ha_myrg= (ha_myisammrg*) callback_param;
218
223
TABLE_LIST *child_l;
220
225
const char *table_name;
257
259
/* Set database (schema) name. */
258
260
child_l->db_length= dirlen;
259
child_l->db= strmake_root(&parent->mem_root, db, dirlen);
261
child_l->db= strmake_root(&ha_myrg->children_mem_root, db, dirlen);
260
262
/* Set table name. */
261
263
child_l->table_name_length= strlen(table_name);
262
child_l->table_name= strmake_root(&parent->mem_root, table_name,
264
child_l->table_name= strmake_root(&ha_myrg->children_mem_root, table_name,
263
265
child_l->table_name_length);
264
266
/* Convert to lowercase if required. */
265
267
if (lower_case_table_names && child_l->table_name_length)
269
/* purecov: begin tested */
266
270
child_l->table_name_length= my_casedn_str(files_charset_info,
267
271
child_l->table_name);
269
275
child_l->alias= child_l->table_name;
271
277
/* Initialize table map to 'undefined'. */
272
278
child_l->init_child_def_version();
274
/* Link TABLE_LIST object into the parent list. */
275
if (!parent->child_last_l)
277
/* Initialize parent->child_last_l when handling first child. */
278
parent->child_last_l= &parent->child_l;
280
*parent->child_last_l= child_l;
281
child_l->prev_global= parent->child_last_l;
282
parent->child_last_l= &child_l->next_global;
289
@brief Callback function for attaching a MERGE child table.
291
@detail This function retrieves the MyISAM table handle from the
292
next child table. It is called for each child table.
294
@param[in] callback_param data pointer as given to
295
myrg_attach_children()
280
/* Link TABLE_LIST object into the children list. */
281
if (ha_myrg->children_last_l)
282
child_l->prev_global= ha_myrg->children_last_l;
285
/* Initialize ha_myrg->children_last_l when handling first child. */
286
ha_myrg->children_last_l= &ha_myrg->children_l;
288
*ha_myrg->children_last_l= child_l;
289
ha_myrg->children_last_l= &child_l->next_global;
296
Open a MERGE parent table, but not its children.
298
@param[in] name MERGE table path name
299
@param[in] mode read/write mode, unused
300
@param[in] test_if_locked open flags
304
@retval -1 Error, my_errno gives reason
307
This function initializes the MERGE storage engine structures
308
and adds a child list of TABLE_LIST to the parent handler.
311
int ha_myisammrg::open(const char *name, int mode __attribute__((unused)),
314
DBUG_ENTER("ha_myisammrg::open");
315
DBUG_PRINT("myrg", ("name: '%s' table: 0x%lx", name, (long) table));
316
DBUG_PRINT("myrg", ("test_if_locked: %u", test_if_locked));
318
/* Must not be used when table is open. */
319
DBUG_ASSERT(!this->file);
321
/* Save for later use. */
322
this->test_if_locked= test_if_locked;
324
/* In case this handler was open and closed before, free old data. */
325
free_root(&this->children_mem_root, MYF(MY_MARK_BLOCKS_FREE));
328
Initialize variables that are used, modified, and/or set by
329
myisammrg_parent_open_callback().
330
'children_l' is the head of the children chain.
331
'children_last_l' points to the end of the children chain.
332
'my_errno' is set by myisammrg_parent_open_callback() in
336
children_last_l= NULL;
339
/* retrieve children table list. */
340
if (!(file= myrg_parent_open(name, myisammrg_parent_open_callback, this)))
342
/* purecov: begin inspected */
343
DBUG_PRINT("error", ("my_errno %d", my_errno));
344
DBUG_RETURN(my_errno ? my_errno : -1);
347
DBUG_PRINT("myrg", ("MYRG_INFO: 0x%lx child tables: %u",
348
(long) file, file->tables));
354
Add list of MERGE children to a TABLE_LIST chain.
361
When a MERGE parent table has just been opened, insert the
362
TABLE_LIST chain from the MERGE handle into the table list used for
363
opening tables for this statement. This lets the children be opened
367
int ha_myisammrg::add_children_list(void)
369
TABLE_LIST *parent_l= this->table->pos_in_table_list;
371
THD *thd= current_thd;
372
DBUG_ENTER("ha_myisammrg::add_children_list");
373
DBUG_PRINT("myrg", ("table: '%s'.'%s' 0x%lx", this->table->s->db.str,
374
this->table->s->table_name.str, (long) this->table));
376
/* Must call this with open table. */
377
DBUG_ASSERT(this->file);
379
/* Ignore this for empty MERGE tables (UNION=()). */
380
if (!this->file->tables)
382
DBUG_PRINT("myrg", ("empty merge table union"));
386
/* Must not call this with attached children. */
387
DBUG_ASSERT(!this->file->children_attached);
389
/* Must not call this with children list in place. */
390
DBUG_ASSERT(parent_l->next_global != this->children_l);
393
Prevent inclusion of another MERGE table, which could make infinite
396
if (parent_l->parent_l)
398
my_error(ER_ADMIN_WRONG_MRG_TABLE, MYF(0), parent_l->alias);
403
DBUG_ASSERT(this->children_l);
404
for (child_l= this->children_l; ; child_l= child_l->next_global)
406
DBUG_ASSERT(!child_l->table);
409
child_l->lock_type= parent_l->lock_type;
411
/* Set parent reference. Used to detect MERGE in children list. */
412
child_l->parent_l= parent_l;
414
/* Copy select_lex. Used in unique_table() at least. */
415
child_l->select_lex= parent_l->select_lex;
417
child_l->mdl_lock_data= NULL; /* Safety, if alloc_mdl_locks fails. */
419
/* Break when this was the last child. */
420
if (&child_l->next_global == this->children_last_l)
424
alloc_mdl_locks(children_l,
425
thd->locked_tables_root ? thd->locked_tables_root :
428
/* Insert children into the table list. */
429
if (parent_l->next_global)
430
parent_l->next_global->prev_global= this->children_last_l;
431
*this->children_last_l= parent_l->next_global;
432
parent_l->next_global= this->children_l;
433
this->children_l->prev_global= &parent_l->next_global;
441
Callback function for attaching a MERGE child table.
443
@param[in] callback_param data pointer as given to myrg_attach_children()
444
this is used to pass the handler handle
297
446
@return pointer to open MyISAM table structure
298
447
@retval !=NULL OK, returning pointer
299
448
@retval NULL, my_errno == 0 Ok, no more child tables
300
449
@retval NULL, my_errno != 0 error
452
This function retrieves the MyISAM table handle from the
453
next child table. It is called for each child table.
303
456
static MI_INFO *myisammrg_attach_children_callback(void *callback_param)
305
ha_myisammrg *ha_myrg;
458
ha_myisammrg *ha_myrg= (ha_myisammrg*) callback_param;
459
TABLE *parent= ha_myrg->table_ptr();
308
461
TABLE_LIST *child_l;
310
463
DBUG_ENTER("myisammrg_attach_children_callback");
313
ha_myrg= (ha_myisammrg*) callback_param;
314
parent= ha_myrg->table_ptr();
316
467
/* Get child list item. */
317
468
child_l= ha_myrg->next_child_attach;
390
@brief Open a MERGE parent table, not its children.
392
@detail This function initializes the MERGE storage engine structures
393
and adds a child list of TABLE_LIST to the parent TABLE.
395
@param[in] name MERGE table path name
396
@param[in] mode read/write mode, unused
397
@param[in] test_if_locked open flags
536
Attach children to a MERGE table.
401
@retval -1 Error, my_errno gives reason
404
int ha_myisammrg::open(const char *name, int mode __attribute__((unused)),
407
DBUG_ENTER("ha_myisammrg::open");
408
DBUG_PRINT("myrg", ("name: '%s' table: 0x%lx", name, (long) table));
409
DBUG_PRINT("myrg", ("test_if_locked: %u", test_if_locked));
411
/* Save for later use. */
412
this->test_if_locked= test_if_locked;
414
/* retrieve children table list. */
416
if (!(file= myrg_parent_open(name, myisammrg_parent_open_callback, this)))
418
DBUG_PRINT("error", ("my_errno %d", my_errno));
419
DBUG_RETURN(my_errno ? my_errno : -1);
421
DBUG_PRINT("myrg", ("MYRG_INFO: 0x%lx", (long) file));
427
@brief Attach children to a MERGE table.
429
@detail Let the storage engine attach its children through a callback
540
@retval != 0 Error, my_errno gives reason
543
Let the storage engine attach its children through a callback
430
544
function. Check table definitions for consistency.
432
@note Special thd->open_options may be in effect. We can make use of
547
Special thd->open_options may be in effect. We can make use of
433
548
them in attach. I.e. we use HA_OPEN_FOR_REPAIR to report the names
434
549
of mismatching child tables. We cannot transport these options in
435
550
ha_myisammrg::test_if_locked because they may change after the
436
551
parent is opened. The parent is kept open in the table cache over
437
552
multiple statements and can be used by other threads. Open options
438
553
can change over time.
442
@retval != 0 Error, my_errno gives reason
445
556
int ha_myisammrg::attach_children(void)
451
562
uint keys= table->s->keys;
453
564
DBUG_ENTER("ha_myisammrg::attach_children");
454
DBUG_PRINT("myrg", ("table: '%s'.'%s' 0x%lx", table->s->db.str,
455
table->s->table_name.str, (long) table));
565
DBUG_PRINT("myrg", ("table: '%s'.'%s' %p", table->s->db.str,
566
table->s->table_name.str, table));
456
567
DBUG_PRINT("myrg", ("test_if_locked: %u", this->test_if_locked));
569
/* Must call this with open table. */
570
DBUG_ASSERT(this->file);
573
A MERGE table with no children (empty union) is always seen as
576
if (!this->file->tables)
578
DBUG_PRINT("myrg", ("empty merge table union"));
581
DBUG_PRINT("myrg", ("child tables: %u", this->file->tables));
583
/* Must not call this with attached children. */
457
584
DBUG_ASSERT(!this->file->children_attached);
586
DEBUG_SYNC(current_thd, "before_myisammrg_attach");
587
/* Must call this with children list in place. */
588
DBUG_ASSERT(this->table->pos_in_table_list->next_global == this->children_l);
460
591
Initialize variables that are used, modified, and/or set by
461
592
myisammrg_attach_children_callback().
567
myrg_detach_children(file);
707
DBUG_PRINT("error", ("attaching MERGE children failed: %d", error));
708
print_error(error, MYF(0));
568
710
DBUG_RETURN(my_errno= error);
573
@brief Detach all children from a MERGE table.
575
@note Detach must not touch the children in any way.
715
Detach all children from a MERGE table and from the query list of tables.
719
@retval != 0 Error, my_errno gives reason
722
Detach must not touch the child TABLE objects in any way.
576
723
They may have been closed at ths point already.
577
724
All references to the children should be removed.
581
@retval != 0 Error, my_errno gives reason
584
727
int ha_myisammrg::detach_children(void)
586
730
DBUG_ENTER("ha_myisammrg::detach_children");
587
DBUG_ASSERT(this->file && this->file->children_attached);
732
/* Must call this with open table. */
733
DBUG_ASSERT(this->file);
735
/* A MERGE table with no children (empty union) cannot be detached. */
736
if (!this->file->tables)
738
DBUG_PRINT("myrg", ("empty merge table union"));
742
/* Clear TABLE references. */
743
DBUG_ASSERT(this->children_l);
744
for (child_l= this->children_l; ; child_l= child_l->next_global)
747
Do not DBUG_ASSERT(child_l->table); open_tables might be
750
Clear the table reference.
752
child_l->table= NULL;
754
/* Break when this was the last child. */
755
if (&child_l->next_global == this->children_last_l)
760
Remove children from the table list. This won't fail if called
761
twice. The list is terminated after removal.
763
If the parent is LEX::query_tables_own_last and pre-locked tables
764
follow (tables used by stored functions or triggers), the children
765
are inserted behind the parent and before the pre-locked tables. But
766
we do not adjust LEX::query_tables_own_last. The pre-locked tables
767
could have chopped off the list by clearing
768
*LEX::query_tables_own_last. This did also chop off the children. If
769
we would copy the reference from *this->children_last_l in this
770
case, we would put the chopped off pre-locked tables back to the
771
list. So we refrain from copying it back, if the destination has
772
been set to NULL meanwhile.
774
if (this->children_l->prev_global && *this->children_l->prev_global)
775
*this->children_l->prev_global= *this->children_last_l;
776
if (*this->children_last_l)
777
(*this->children_last_l)->prev_global= this->children_l->prev_global;
779
/* Terminate child list. So it cannot be tried to remove again. */
780
*this->children_last_l= NULL;
781
this->children_l->prev_global= NULL;
783
if (!this->file->children_attached)
785
DBUG_PRINT("myrg", ("merge children are already detached"));
589
789
if (myrg_detach_children(this->file))
591
791
/* purecov: begin inspected */
592
DBUG_PRINT("error", ("my_errno %d", my_errno));
792
print_error(my_errno, MYF(0));
593
793
DBUG_RETURN(my_errno ? my_errno : -1);
594
794
/* purecov: end */
601
@brief Close a MERGE parent table, not its children.
603
@note The children are expected to be closed separately by the caller.
803
Close a MERGE parent table, but not its children.
607
807
@retval != 0 Error, my_errno gives reason
810
The children are expected to be closed separately by the caller.
610
813
int ha_myisammrg::close(void)