~jlukas79/+junk/mysql-server

« back to all changes in this revision

Viewing changes to storage/myisammrg/ha_myisammrg.cc

manual merge 6.0-main --> 6.0-bka-review

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
38
 
  TABLE::child_last_l.
39
 
 
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.
48
 
 
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.
54
 
 
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.
 
39
 
 
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
 
48
  statement.
 
49
 
 
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.
59
54
 
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.
63
58
 
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.
69
 
 
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
80
69
  myisammrg_attach_children_callback() sets it ot TRUE if a table
81
70
  def version mismatches the remembered child def version.
82
71
 
83
 
  Finally the parent TABLE::children_attached is set.
 
72
  The children chain remains in the statement query list until the table
 
73
  is closed or the children are detached. This is done so that the
 
74
  children are locked by lock_tables().
 
75
 
 
76
  At statement end the children are detached. At the next statement
 
77
  begin the open-add-attach sequence repeats. There is no exception for
 
78
  LOCK TABLES. The fresh establishment of the parent-child relationship
 
79
  before every statement catches numerous cases of ALTER/FLUSH/DROP/etc
 
80
  of parent or children during LOCK TABLES.
84
81
 
85
82
  ---
86
83
 
87
84
  On parent open the storage engine structures are allocated and initialized.
88
85
  They stay with the open table until its final close.
89
 
 
90
 
 
91
86
*/
92
87
 
93
88
#ifdef USE_PRAGMA_IMPLEMENTATION
117
112
 
118
113
ha_myisammrg::ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg)
119
114
  :handler(hton, table_arg), file(0)
120
 
{}
 
115
{
 
116
  init_sql_alloc(&children_mem_root, max(4 * sizeof(TABLE_LIST), FN_REFLEN) +
 
117
                 ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
 
118
}
121
119
 
122
120
 
123
121
/**
125
123
*/
126
124
 
127
125
ha_myisammrg::~ha_myisammrg(void)
128
 
{}
 
126
{
 
127
  free_root(&children_mem_root, MYF(0));
 
128
}
129
129
 
130
130
 
131
131
static const char *ha_myisammrg_exts[] = {
134
134
};
135
135
extern int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
136
136
                        MI_COLUMNDEF **recinfo_out, uint *records_out);
137
 
extern int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
 
137
extern int check_definition(MI_KEYDEF *t1_keyinfo,
 
138
                            MI_COLUMNDEF *t1_recinfo,
138
139
                            uint t1_keys, uint t1_recs,
139
 
                            MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
 
140
                            MI_KEYDEF *t2_keyinfo,
 
141
                            MI_COLUMNDEF *t2_recinfo,
140
142
                            uint t2_keys, uint t2_recs, bool strict);
141
143
static void split_file_name(const char *file_name,
142
144
                            LEX_STRING *db, LEX_STRING *name);
176
178
 
177
179
 
178
180
/**
179
 
  @brief Callback function for open of a MERGE parent table.
180
 
 
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
183
 
    each child table.
184
 
 
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.
190
 
 
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.
194
 
 
195
 
    TABLE::child_l -> TABLE_LIST::next_global -> TABLE_LIST::next_global
196
 
    #                 #               ^          #               ^
197
 
    #                 #               |          #               |
198
 
    #                 #               +--------- TABLE_LIST::prev_global
199
 
    #                 #                                          |
200
 
    #           |<--- TABLE_LIST::prev_global                    |
201
 
    #                                                            |
202
 
    TABLE::child_last_l -----------------------------------------+
 
181
  Callback function for open of a MERGE parent table.
203
182
 
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.
207
187
 
208
188
  @return status
209
189
    @retval     0               OK
210
190
    @retval     != 0            Error
 
191
 
 
192
  @detail
 
193
 
 
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
 
196
    child table.
 
197
 
 
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.
 
203
 
 
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.
 
208
 
 
209
    children_l -> TABLE_LIST::next_global -> TABLE_LIST::next_global
 
210
    #             #               ^          #               ^
 
211
    #             #               |          #               |
 
212
    #             #               +--------- TABLE_LIST::prev_global
 
213
    #             #                                          |
 
214
    #       |<--- TABLE_LIST::prev_global                    |
 
215
    #                                                        |
 
216
    children_last_l -----------------------------------------+
211
217
*/
212
218
 
213
219
static int myisammrg_parent_open_callback(void *callback_param,
214
220
                                          const char *filename)
215
221
{
216
 
  ha_myisammrg  *ha_myrg;
217
 
  TABLE         *parent;
 
222
  ha_myisammrg  *ha_myrg= (ha_myisammrg*) callback_param;
218
223
  TABLE_LIST    *child_l;
219
224
  const char    *db;
220
225
  const char    *table_name;
240
245
  dirlen-= db - dir_path; /* This is now the length of 'db'. */
241
246
  DBUG_PRINT("myrg", ("open: '%s'.'%s'", db, table_name));
242
247
 
243
 
  ha_myrg= (ha_myisammrg*) callback_param;
244
 
  parent= ha_myrg->table_ptr();
245
 
 
246
248
  /* Get a TABLE_LIST object. */
247
 
  if (!(child_l= (TABLE_LIST*) alloc_root(&parent->mem_root,
 
249
  if (!(child_l= (TABLE_LIST*) alloc_root(&ha_myrg->children_mem_root,
248
250
                                          sizeof(TABLE_LIST))))
249
251
  {
250
252
    /* purecov: begin inspected */
256
258
 
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)
 
268
  {
 
269
    /* purecov: begin tested */
266
270
    child_l->table_name_length= my_casedn_str(files_charset_info,
267
271
                                              child_l->table_name);
 
272
    /* purecov: end */
 
273
  }
268
274
  /* Set alias. */
269
275
  child_l->alias= child_l->table_name;
270
276
 
271
277
  /* Initialize table map to 'undefined'. */
272
278
  child_l->init_child_def_version();
273
279
 
274
 
  /* Link TABLE_LIST object into the parent list. */
275
 
  if (!parent->child_last_l)
276
 
  {
277
 
    /* Initialize parent->child_last_l when handling first child. */
278
 
    parent->child_last_l= &parent->child_l;
279
 
  }
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;
283
 
 
284
 
  DBUG_RETURN(0);
285
 
}
286
 
 
287
 
 
288
 
/**
289
 
  @brief Callback function for attaching a MERGE child table.
290
 
 
291
 
  @detail This function retrieves the MyISAM table handle from the
292
 
    next child table. It is called for each child table.
293
 
 
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;
 
283
  else
 
284
  {
 
285
    /* Initialize ha_myrg->children_last_l when handling first child. */
 
286
    ha_myrg->children_last_l= &ha_myrg->children_l;
 
287
  }
 
288
  *ha_myrg->children_last_l= child_l;
 
289
  ha_myrg->children_last_l= &child_l->next_global;
 
290
 
 
291
  DBUG_RETURN(0);
 
292
}
 
293
 
 
294
 
 
295
/**
 
296
  Open a MERGE parent table, but not its children.
 
297
 
 
298
  @param[in]    name            MERGE table path name
 
299
  @param[in]    mode            read/write mode, unused
 
300
  @param[in]    test_if_locked  open flags
 
301
 
 
302
  @return       status
 
303
  @retval     0               OK
 
304
  @retval     -1              Error, my_errno gives reason
 
305
 
 
306
  @detail
 
307
  This function initializes the MERGE storage engine structures
 
308
  and adds a child list of TABLE_LIST to the parent handler.
 
309
*/
 
310
 
 
311
int ha_myisammrg::open(const char *name, int mode __attribute__((unused)),
 
312
                       uint test_if_locked)
 
313
{
 
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));
 
317
 
 
318
  /* Must not be used when table is open. */
 
319
  DBUG_ASSERT(!this->file);
 
320
 
 
321
  /* Save for later use. */
 
322
  this->test_if_locked= test_if_locked;
 
323
 
 
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));
 
326
 
 
327
  /*
 
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
 
333
    case of an error.
 
334
  */
 
335
  children_l= NULL;
 
336
  children_last_l= NULL;
 
337
  my_errno= 0;
 
338
 
 
339
  /* retrieve children table list. */
 
340
  if (!(file= myrg_parent_open(name, myisammrg_parent_open_callback, this)))
 
341
  {
 
342
    /* purecov: begin inspected */
 
343
    DBUG_PRINT("error", ("my_errno %d", my_errno));
 
344
    DBUG_RETURN(my_errno ? my_errno : -1);
 
345
    /* purecov: end */
 
346
  }
 
347
  DBUG_PRINT("myrg", ("MYRG_INFO: 0x%lx  child tables: %u",
 
348
                      (long) file, file->tables));
 
349
  DBUG_RETURN(0);
 
350
}
 
351
 
 
352
 
 
353
/**
 
354
  Add list of MERGE children to a TABLE_LIST chain.
 
355
 
 
356
  @return status
 
357
    @retval     0               OK
 
358
    @retval     != 0            Error
 
359
 
 
360
  @detail
 
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
 
364
    too.
 
365
*/
 
366
 
 
367
int ha_myisammrg::add_children_list(void)
 
368
{
 
369
  TABLE_LIST  *parent_l= this->table->pos_in_table_list;
 
370
  TABLE_LIST  *child_l;
 
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));
 
375
 
 
376
  /* Must call this with open table. */
 
377
  DBUG_ASSERT(this->file);
 
378
 
 
379
  /* Ignore this for empty MERGE tables (UNION=()). */
 
380
  if (!this->file->tables)
 
381
  {
 
382
    DBUG_PRINT("myrg", ("empty merge table union"));
 
383
    goto end;
 
384
  }
 
385
 
 
386
  /* Must not call this with attached children. */
 
387
  DBUG_ASSERT(!this->file->children_attached);
 
388
 
 
389
  /* Must not call this with children list in place. */
 
390
  DBUG_ASSERT(parent_l->next_global != this->children_l);
 
391
 
 
392
  /*
 
393
    Prevent inclusion of another MERGE table, which could make infinite
 
394
    recursion.
 
395
  */
 
396
  if (parent_l->parent_l)
 
397
  {
 
398
    my_error(ER_ADMIN_WRONG_MRG_TABLE, MYF(0), parent_l->alias);
 
399
    DBUG_RETURN(1);
 
400
  }
 
401
 
 
402
  /* Fix children. */
 
403
  DBUG_ASSERT(this->children_l);
 
404
  for (child_l= this->children_l; ; child_l= child_l->next_global)
 
405
  {
 
406
    DBUG_ASSERT(!child_l->table);
 
407
 
 
408
    /* Set lock type. */
 
409
    child_l->lock_type= parent_l->lock_type;
 
410
 
 
411
    /* Set parent reference. Used to detect MERGE in children list. */
 
412
    child_l->parent_l= parent_l;
 
413
 
 
414
    /* Copy select_lex. Used in unique_table() at least. */
 
415
    child_l->select_lex= parent_l->select_lex;
 
416
 
 
417
    child_l->mdl_lock_data= NULL; /* Safety, if alloc_mdl_locks fails. */
 
418
 
 
419
    /* Break when this was the last child. */
 
420
    if (&child_l->next_global == this->children_last_l)
 
421
      break;
 
422
  }
 
423
 
 
424
  alloc_mdl_locks(children_l,
 
425
                  thd->locked_tables_root ? thd->locked_tables_root :
 
426
                  thd->mem_root);
 
427
 
 
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;
 
434
 
 
435
end:
 
436
  DBUG_RETURN(0);
 
437
}
 
438
 
 
439
 
 
440
/**
 
441
  Callback function for attaching a MERGE child table.
 
442
 
 
443
  @param[in]    callback_param  data pointer as given to myrg_attach_children()
 
444
                                this is used to pass the handler handle
296
445
 
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
 
450
 
 
451
  @detail
 
452
    This function retrieves the MyISAM table handle from the
 
453
    next child table. It is called for each child table.
301
454
*/
302
455
 
303
456
static MI_INFO *myisammrg_attach_children_callback(void *callback_param)
304
457
{
305
 
  ha_myisammrg  *ha_myrg;
306
 
  TABLE         *parent;
 
458
  ha_myisammrg  *ha_myrg= (ha_myisammrg*) callback_param;
 
459
  TABLE         *parent= ha_myrg->table_ptr();
307
460
  TABLE         *child;
308
461
  TABLE_LIST    *child_l;
309
462
  MI_INFO       *myisam;
310
463
  DBUG_ENTER("myisammrg_attach_children_callback");
311
464
 
312
465
  my_errno= 0;
313
 
  ha_myrg= (ha_myisammrg*) callback_param;
314
 
  parent= ha_myrg->table_ptr();
315
466
 
316
467
  /* Get child list item. */
317
468
  child_l= ha_myrg->next_child_attach;
321
472
    DBUG_RETURN(NULL);
322
473
  }
323
474
  child= child_l->table;
324
 
  DBUG_PRINT("myrg", ("child table: '%s'.'%s' 0x%lx", child->s->db.str,
325
 
                      child->s->table_name.str, (long) child));
326
475
  /*
327
476
    Prepare for next child. Used as child_l in next call to this function.
328
477
    We cannot rely on a NULL-terminated chain.
329
478
  */
330
 
  if (&child_l->next_global == parent->child_last_l)
 
479
  if (&child_l->next_global == ha_myrg->children_last_l)
331
480
  {
332
481
    DBUG_PRINT("myrg", ("attaching last child"));
333
482
    ha_myrg->next_child_attach= NULL;
335
484
  else
336
485
    ha_myrg->next_child_attach= child_l->next_global;
337
486
 
338
 
  /* Set parent reference. */
339
 
  child->parent= parent;
340
 
 
341
487
  /*
342
488
    Do a quick compatibility check. The table def version is set when
343
489
    the table share is created. The child def version is copied
373
519
  if ((child->file->ht->db_type != DB_TYPE_MYISAM) ||
374
520
      !(myisam= ((ha_myisam*) child->file)->file_ptr()))
375
521
  {
376
 
    DBUG_PRINT("error", ("no MyISAM handle for child table: '%s'.'%s' 0x%lx",
 
522
    DBUG_PRINT("error", ("no MyISAM handle for child table: '%s'.'%s' %p",
377
523
                         child->s->db.str, child->s->table_name.str,
378
 
                         (long) child));
 
524
                         child));
379
525
    my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
380
526
  }
381
 
  DBUG_PRINT("myrg", ("MyISAM handle: 0x%lx  my_errno: %d",
382
 
                      (long) myisam, my_errno));
 
527
  DBUG_PRINT("myrg", ("MyISAM handle: %p  my_errno: %d",
 
528
                      myisam, my_errno));
383
529
 
384
530
 err:
385
531
  DBUG_RETURN(my_errno ? NULL : myisam);
387
533
 
388
534
 
389
535
/**
390
 
  @brief Open a MERGE parent table, not its children.
391
 
 
392
 
  @detail This function initializes the MERGE storage engine structures
393
 
    and adds a child list of TABLE_LIST to the parent TABLE.
394
 
 
395
 
  @param[in]    name            MERGE table path name
396
 
  @param[in]    mode            read/write mode, unused
397
 
  @param[in]    test_if_locked  open flags
398
 
 
399
 
  @return       status
 
536
  Attach children to a MERGE table.
 
537
 
 
538
  @return status
400
539
    @retval     0               OK
401
 
    @retval     -1              Error, my_errno gives reason
402
 
*/
403
 
 
404
 
int ha_myisammrg::open(const char *name, int mode __attribute__((unused)),
405
 
                       uint test_if_locked)
406
 
{
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));
410
 
 
411
 
  /* Save for later use. */
412
 
  this->test_if_locked= test_if_locked;
413
 
 
414
 
  /* retrieve children table list. */
415
 
  my_errno= 0;
416
 
  if (!(file= myrg_parent_open(name, myisammrg_parent_open_callback, this)))
417
 
  {
418
 
    DBUG_PRINT("error", ("my_errno %d", my_errno));
419
 
    DBUG_RETURN(my_errno ? my_errno : -1);
420
 
  }
421
 
  DBUG_PRINT("myrg", ("MYRG_INFO: 0x%lx", (long) file));
422
 
  DBUG_RETURN(0);
423
 
}
424
 
 
425
 
 
426
 
/**
427
 
  @brief Attach children to a MERGE table.
428
 
 
429
 
  @detail Let the storage engine attach its children through a callback
 
540
    @retval     != 0            Error, my_errno gives reason
 
541
 
 
542
  @detail
 
543
    Let the storage engine attach its children through a callback
430
544
    function. Check table definitions for consistency.
431
545
 
432
 
  @note Special thd->open_options may be in effect. We can make use of
 
546
  @note
 
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.
439
 
 
440
 
  @return status
441
 
    @retval     0               OK
442
 
    @retval     != 0            Error, my_errno gives reason
443
554
*/
444
555
 
445
556
int ha_myisammrg::attach_children(void)
451
562
  uint          keys= table->s->keys;
452
563
  int           error;
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));
 
568
 
 
569
  /* Must call this with open table. */
 
570
  DBUG_ASSERT(this->file);
 
571
 
 
572
  /*
 
573
    A MERGE table with no children (empty union) is always seen as
 
574
    attached internally.
 
575
  */
 
576
  if (!this->file->tables)
 
577
  {
 
578
    DBUG_PRINT("myrg", ("empty merge table union"));
 
579
    goto end;
 
580
  }
 
581
  DBUG_PRINT("myrg", ("child tables: %u", this->file->tables));
 
582
 
 
583
  /* Must not call this with attached children. */
457
584
  DBUG_ASSERT(!this->file->children_attached);
458
585
 
 
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);
 
589
 
459
590
  /*
460
591
    Initialize variables that are used, modified, and/or set by
461
592
    myisammrg_attach_children_callback().
468
599
    'my_errno' is set by myisammrg_attach_children_callback() in
469
600
    case of an error.
470
601
  */
471
 
  next_child_attach= table->child_l;
 
602
  next_child_attach= this->children_l;
472
603
  need_compat_check= FALSE;
473
604
  my_errno= 0;
474
605
 
476
607
                           current_thd->open_options,
477
608
                           myisammrg_attach_children_callback, this))
478
609
  {
479
 
    DBUG_PRINT("error", ("my_errno %d", my_errno));
480
 
    DBUG_RETURN(my_errno ? my_errno : -1);
 
610
    error= my_errno;
 
611
    goto err;
481
612
  }
482
613
  DBUG_PRINT("myrg", ("calling myrg_extrafunc"));
483
614
  myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref);
504
635
      DBUG_PRINT("error",("reclength: %lu  mean_rec_length: %lu",
505
636
                          table->s->reclength, stats.mean_rec_length));
506
637
      if (test_if_locked & HA_OPEN_FOR_REPAIR)
507
 
        myrg_print_wrong_table(file->open_tables->table->filename);
 
638
      {
 
639
        /* purecov: begin inspected */
 
640
        myrg_print_wrong_table(file->open_tables->table->s->unresolv_file_name);
 
641
        /* purecov: end */
 
642
      }
508
643
      error= HA_ERR_WRONG_MRG_TABLE_DEF;
509
644
      goto err;
510
645
    }
528
663
                           u_table->table->s->base.fields, false))
529
664
      {
530
665
        DBUG_PRINT("error", ("table definition mismatch: '%s'",
531
 
                             u_table->table->filename));
 
666
                             u_table->table->s->unresolv_file_name));
532
667
        error= HA_ERR_WRONG_MRG_TABLE_DEF;
533
668
        if (!(this->test_if_locked & HA_OPEN_FOR_REPAIR))
534
669
        {
535
670
          my_free((uchar*) recinfo, MYF(0));
536
671
          goto err;
537
672
        }
538
 
        myrg_print_wrong_table(u_table->table->filename);
 
673
        /* purecov: begin inspected */
 
674
        myrg_print_wrong_table(u_table->table->s->unresolv_file_name);
 
675
        /* purecov: end */
539
676
      }
540
677
    }
541
678
    my_free((uchar*) recinfo, MYF(0));
542
679
    if (error == HA_ERR_WRONG_MRG_TABLE_DEF)
543
 
      goto err;
 
680
      goto err; /* purecov: inspected */
544
681
 
545
682
    /* All checks passed so far. Now update child def version. */
546
 
    for (child_l= table->child_l; ; child_l= child_l->next_global)
 
683
    DBUG_ASSERT(this->children_l);
 
684
    for (child_l= this->children_l; ; child_l= child_l->next_global)
547
685
    {
548
686
      child_l->set_child_def_version(
549
687
        child_l->table->s->get_table_def_version());
550
688
 
551
 
      if (&child_l->next_global == table->child_last_l)
 
689
      if (&child_l->next_global == this->children_last_l)
552
690
        break;
553
691
    }
554
692
  }
561
699
    goto err;
562
700
  }
563
701
#endif
 
702
 
 
703
 end:
564
704
  DBUG_RETURN(0);
565
705
 
566
706
err:
567
 
  myrg_detach_children(file);
 
707
  DBUG_PRINT("error", ("attaching MERGE children failed: %d", error));
 
708
  print_error(error, MYF(0));
 
709
  detach_children();
568
710
  DBUG_RETURN(my_errno= error);
569
711
}
570
712
 
571
713
 
572
714
/**
573
 
  @brief Detach all children from a MERGE table.
574
 
 
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.
 
716
 
 
717
  @return status
 
718
    @retval     0               OK
 
719
    @retval     != 0            Error, my_errno gives reason
 
720
 
 
721
  @note
 
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.
578
 
 
579
 
  @return status
580
 
    @retval     0               OK
581
 
    @retval     != 0            Error, my_errno gives reason
582
725
*/
583
726
 
584
727
int ha_myisammrg::detach_children(void)
585
728
{
 
729
  TABLE_LIST *child_l;
586
730
  DBUG_ENTER("ha_myisammrg::detach_children");
587
 
  DBUG_ASSERT(this->file && this->file->children_attached);
 
731
 
 
732
  /* Must call this with open table. */
 
733
  DBUG_ASSERT(this->file);
 
734
 
 
735
  /* A MERGE table with no children (empty union) cannot be detached. */
 
736
  if (!this->file->tables)
 
737
  {
 
738
    DBUG_PRINT("myrg", ("empty merge table union"));
 
739
    goto end;
 
740
  }
 
741
 
 
742
  /* Clear TABLE references. */
 
743
  DBUG_ASSERT(this->children_l);
 
744
  for (child_l= this->children_l; ; child_l= child_l->next_global)
 
745
  {
 
746
    /*
 
747
      Do not DBUG_ASSERT(child_l->table); open_tables might be
 
748
      incomplete.
 
749
 
 
750
      Clear the table reference.
 
751
    */
 
752
    child_l->table= NULL;
 
753
 
 
754
    /* Break when this was the last child. */
 
755
    if (&child_l->next_global == this->children_last_l)
 
756
      break;
 
757
  }
 
758
 
 
759
  /*
 
760
    Remove children from the table list. This won't fail if called
 
761
    twice. The list is terminated after removal.
 
762
 
 
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.
 
773
  */
 
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;
 
778
 
 
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;
 
782
 
 
783
  if (!this->file->children_attached)
 
784
  {
 
785
    DBUG_PRINT("myrg", ("merge children are already detached"));
 
786
    goto end;
 
787
  }
588
788
 
589
789
  if (myrg_detach_children(this->file))
590
790
  {
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 */
595
795
  }
 
796
 
 
797
 end:
596
798
  DBUG_RETURN(0);
597
799
}
598
800
 
599
801
 
600
802
/**
601
 
  @brief Close a MERGE parent table, not its children.
602
 
 
603
 
  @note The children are expected to be closed separately by the caller.
 
803
  Close a MERGE parent table, but not its children.
604
804
 
605
805
  @return status
606
806
    @retval     0               OK
607
807
    @retval     != 0            Error, my_errno gives reason
 
808
 
 
809
  @note
 
810
    The children are expected to be closed separately by the caller.
608
811
*/
609
812
 
610
813
int ha_myisammrg::close(void)
612
815
  int rc;
613
816
  DBUG_ENTER("ha_myisammrg::close");
614
817
  /*
615
 
    Children must not be attached here. Unless the MERGE table has no
616
 
    children. In this case children_attached is always true.
 
818
    There are cases where children are not explicitly detached before
 
819
    close. detach_children() protects itself against double detach.
617
820
  */
618
 
  DBUG_ASSERT(!this->file->children_attached || !this->file->tables);
 
821
  detach_children();
 
822
 
619
823
  rc= myrg_close(file);
620
824
  file= 0;
621
825
  DBUG_RETURN(rc);
857
1061
 
858
1062
int ha_myisammrg::extra(enum ha_extra_function operation)
859
1063
{
860
 
  if (operation == HA_EXTRA_ATTACH_CHILDREN)
 
1064
  if (operation == HA_EXTRA_ADD_CHILDREN_LIST)
 
1065
  {
 
1066
    int rc= add_children_list();
 
1067
    return(rc);
 
1068
  }
 
1069
  else if (operation == HA_EXTRA_ATTACH_CHILDREN)
861
1070
  {
862
1071
    int rc= attach_children();
863
1072
    if (!rc)
864
1073
      (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
865
1074
    return(rc);
866
1075
  }
 
1076
  else if (operation == HA_EXTRA_IS_ATTACHED_CHILDREN)
 
1077
  {
 
1078
    /* For the upper layer pretend empty MERGE union is never attached. */
 
1079
    return(file && file->tables && file->children_attached);
 
1080
  }
867
1081
  else if (operation == HA_EXTRA_DETACH_CHILDREN)
868
1082
  {
869
1083
    /*
877
1091
  /* As this is just a mapping, we don't have to force the underlying
878
1092
     tables to be closed */
879
1093
  if (operation == HA_EXTRA_FORCE_REOPEN ||
880
 
      operation == HA_EXTRA_PREPARE_FOR_DELETE)
 
1094
      operation == HA_EXTRA_PREPARE_FOR_DROP ||
 
1095
      operation == HA_EXTRA_PREPARE_FOR_RENAME)
881
1096
    return 0;
882
1097
  return myrg_extra(file,operation,0);
883
1098
}
884
1099
 
885
1100
int ha_myisammrg::reset(void)
886
1101
{
 
1102
  /* This is normally called with detached children. */
887
1103
  return myrg_reset(file);
888
1104
}
889
1105
 
899
1115
 
900
1116
int ha_myisammrg::external_lock(THD *thd, int lock_type)
901
1117
{
902
 
  MYRG_TABLE *tmp;
903
 
  DBUG_ASSERT(this->file->children_attached);
904
 
  for (tmp= file->open_tables; tmp != file->end_table; tmp++)
905
 
    tmp->table->in_use.data= thd;
906
 
  return myrg_lock_database(file,lock_type);
 
1118
  /*
 
1119
    This can be called with no children attached. E.g. FLUSH TABLES
 
1120
    unlocks and re-locks tables under LOCK TABLES, but it does not open
 
1121
    them first. So they are detached all the time. But locking of the
 
1122
    children should work anyway because thd->open_tables is not changed
 
1123
    during FLUSH TABLES.
 
1124
  */
 
1125
  return 0;
907
1126
}
908
1127
 
909
1128
uint ha_myisammrg::lock_count(void) const
910
1129
{
911
 
  /*
912
 
    Return the real lock count even if the children are not attached.
913
 
    This method is used for allocating memory. If we would return 0
914
 
    to another thread (e.g. doing FLUSH TABLE), and attach the children
915
 
    before the other thread calls store_lock(), then we would return
916
 
    more locks in store_lock() than we claimed by lock_count(). The
917
 
    other tread would overrun its memory.
918
 
  */
919
 
  return file->tables;
 
1130
  return 0;
920
1131
}
921
1132
 
922
1133
 
924
1135
                                         THR_LOCK_DATA **to,
925
1136
                                         enum thr_lock_type lock_type)
926
1137
{
927
 
  MYRG_TABLE *open_table;
928
 
 
929
 
  /*
930
 
    This method can be called while another thread is attaching the
931
 
    children. If the processor reorders instructions or write to memory,
932
 
    'children_attached' could be set before 'open_tables' has all the
933
 
    pointers to the children. Use of a mutex here and in
934
 
    myrg_attach_children() forces consistent data.
935
 
  */
936
 
  pthread_mutex_lock(&this->file->mutex);
937
 
 
938
 
  /*
939
 
    When MERGE table is open, but not yet attached, other threads
940
 
    could flush it, which means call mysql_lock_abort_for_thread()
941
 
    on this threads TABLE. 'children_attached' is FALSE in this
942
 
    situaton. Since the table is not locked, return no lock data.
943
 
  */
944
 
  if (!this->file->children_attached)
945
 
    goto end; /* purecov: tested */
946
 
 
947
 
  for (open_table=file->open_tables ;
948
 
       open_table != file->end_table ;
949
 
       open_table++)
950
 
  {
951
 
    *(to++)= &open_table->table->lock;
952
 
    if (lock_type != TL_IGNORE && open_table->table->lock.type == TL_UNLOCK)
953
 
      open_table->table->lock.type=lock_type;
954
 
  }
955
 
 
956
 
 end:
957
 
  pthread_mutex_unlock(&this->file->mutex);
 
1138
  DEBUG_SYNC(thd, "before_myisammrg_store_lock");
 
1139
 
958
1140
  return to;
959
1141
}
960
1142
 
1005
1187
 
1006
1188
      if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
1007
1189
        goto err;
1008
 
      split_file_name(open_table->table->filename, &db, &name);
 
1190
      split_file_name(open_table->table->s->unresolv_file_name, &db, &name);
1009
1191
      if (!(ptr->table_name= thd->strmake(name.str, name.length)))
1010
1192
        goto err;
1011
1193
      if (db.length && !(ptr->db= thd->strmake(db.str, db.length)))
1043
1225
  /* Allocate a table_names array in thread mem_root. */
1044
1226
  if (!(table_names= (const char**)
1045
1227
        thd->alloc((create_info->merge_list.elements+1) * sizeof(char*))))
1046
 
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
 
1228
    DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
1047
1229
 
1048
1230
  /* Create child path names. */
1049
1231
  for (pos= table_names; tables; tables= tables->next_local)
1123
1305
    LEX_STRING db, name;
1124
1306
    LINT_INIT(db.str);
1125
1307
 
1126
 
    split_file_name(open_table->table->filename, &db, &name);
 
1308
    split_file_name(open_table->table->s->unresolv_file_name, &db, &name);
1127
1309
    if (open_table != first)
1128
1310
      packet->append(',');
1129
1311
    /* Report database for mapped table if it isn't in current database */
1153
1335
 
1154
1336
int ha_myisammrg::check(THD* thd, HA_CHECK_OPT* check_opt)
1155
1337
{
1156
 
  return HA_ADMIN_OK;
 
1338
  return this->file->children_attached ? HA_ADMIN_OK : HA_ADMIN_CORRUPT;
 
1339
}
 
1340
 
 
1341
 
 
1342
ha_rows ha_myisammrg::records()
 
1343
{
 
1344
  return myrg_records(file);
1157
1345
}
1158
1346
 
1159
1347