~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to storage/myisammrg/ha_myisammrg.cc

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2006 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
13
   along with this program; if not, write to the Free Software
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
/*
 
18
  MyISAM MERGE tables
 
19
 
 
20
  A MyISAM MERGE table is kind of a union of zero or more MyISAM tables.
 
21
 
 
22
  Besides the normal form file (.frm) a MERGE table has a meta file
 
23
  (.MRG) with a list of tables. These are paths to the MyISAM table
 
24
  files. The last two components of the path contain the database name
 
25
  and the table name respectively.
 
26
 
 
27
  When a MERGE table is open, there exists an TABLE object for the MERGE
 
28
  table itself and a TABLE object for each of the MyISAM tables. For
 
29
  abbreviated writing, I call the MERGE table object "parent" and the
 
30
  MyISAM table objects "children".
 
31
 
 
32
  A MERGE table is almost always opened through open_and_lock_tables()
 
33
  and hence through open_tables(). When the parent appears in the list
 
34
  of tables to open, the initial open of the handler does nothing but
 
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
 
58
  children are set up.
 
59
 
 
60
  The MERGE storage engine sets up an array with references to the
 
61
  low-level MyISAM table objects (MI_INFO). It remembers the state of
 
62
  the table in MYRG_INFO::children_attached.
 
63
 
 
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
  If necessary, the compatibility of parent and children is checked.
 
71
  This check is necessary when any of the objects are reopend. This is
 
72
  detected by comparing the current table def version against the
 
73
  remembered child def version. On parent open, the list members are
 
74
  initialized to an "impossible"/"undefined" version value. So the check
 
75
  is always executed on the first attach.
 
76
 
 
77
  The version check is done in myisammrg_attach_children_callback(),
 
78
  which is called for every child. ha_myisammrg::attach_children()
 
79
  initializes 'need_compat_check' to FALSE and
 
80
  myisammrg_attach_children_callback() sets it ot TRUE if a table
 
81
  def version mismatches the remembered child def version.
 
82
 
 
83
  Finally the parent TABLE::children_attached is set.
 
84
 
 
85
  ---
 
86
 
 
87
  On parent open the storage engine structures are allocated and initialized.
 
88
  They stay with the open table until its final close.
 
89
 
 
90
 
 
91
*/
 
92
 
 
93
#ifdef USE_PRAGMA_IMPLEMENTATION
 
94
#pragma implementation                          // gcc: Class implementation
 
95
#endif
 
96
 
 
97
#define MYSQL_SERVER 1
 
98
#include "mysql_priv.h"
 
99
#include <mysql/plugin.h>
 
100
#include <m_ctype.h>
 
101
#include "../myisam/ha_myisam.h"
 
102
#include "ha_myisammrg.h"
 
103
#include "myrg_def.h"
 
104
 
 
105
 
 
106
static handler *myisammrg_create_handler(handlerton *hton,
 
107
                                         TABLE_SHARE *table,
 
108
                                         MEM_ROOT *mem_root)
 
109
{
 
110
  return new (mem_root) ha_myisammrg(hton, table);
 
111
}
 
112
 
 
113
 
 
114
/**
 
115
  @brief Constructor
 
116
*/
 
117
 
 
118
ha_myisammrg::ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg)
 
119
  :handler(hton, table_arg), file(0), is_cloned(0)
 
120
{}
 
121
 
 
122
 
 
123
/**
 
124
  @brief Destructor
 
125
*/
 
126
 
 
127
ha_myisammrg::~ha_myisammrg(void)
 
128
{}
 
129
 
 
130
 
 
131
static const char *ha_myisammrg_exts[] = {
 
132
  ".MRG",
 
133
  NullS
 
134
};
 
135
extern int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
 
136
                        MI_COLUMNDEF **recinfo_out, uint *records_out);
 
137
extern int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
 
138
                            uint t1_keys, uint t1_recs,
 
139
                            MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
 
140
                            uint t2_keys, uint t2_recs, bool strict,
 
141
                            TABLE *table_arg);
 
142
static void split_file_name(const char *file_name,
 
143
                            LEX_STRING *db, LEX_STRING *name);
 
144
 
 
145
 
 
146
extern "C" void myrg_print_wrong_table(const char *table_name)
 
147
{
 
148
  LEX_STRING db= {NULL, 0}, name;
 
149
  char buf[FN_REFLEN];
 
150
  split_file_name(table_name, &db, &name);
 
151
  memcpy(buf, db.str, db.length);
 
152
  buf[db.length]= '.';
 
153
  memcpy(buf + db.length + 1, name.str, name.length);
 
154
  buf[db.length + name.length + 1]= 0;
 
155
  push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
 
156
                      ER_ADMIN_WRONG_MRG_TABLE, ER(ER_ADMIN_WRONG_MRG_TABLE),
 
157
                      buf);
 
158
}
 
159
 
 
160
 
 
161
const char **ha_myisammrg::bas_ext() const
 
162
{
 
163
  return ha_myisammrg_exts;
 
164
}
 
165
 
 
166
 
 
167
const char *ha_myisammrg::index_type(uint key_number)
 
168
{
 
169
  return ((table->key_info[key_number].flags & HA_FULLTEXT) ? 
 
170
          "FULLTEXT" :
 
171
          (table->key_info[key_number].flags & HA_SPATIAL) ?
 
172
          "SPATIAL" :
 
173
          (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
 
174
          "RTREE" :
 
175
          "BTREE");
 
176
}
 
177
 
 
178
 
 
179
/**
 
180
  @brief Callback function for open of a MERGE parent table.
 
181
 
 
182
  @detail This function adds a TABLE_LIST object for a MERGE child table
 
183
    to a list of tables of the parent TABLE object. It is called for
 
184
    each child table.
 
185
 
 
186
    The list of child TABLE_LIST objects is kept in the TABLE object of
 
187
    the parent for the whole life time of the MERGE table. It is
 
188
    inserted in the statement list behind the MERGE parent TABLE_LIST
 
189
    object when the MERGE table is opened. It is removed from the
 
190
    statement list after the last child is opened.
 
191
 
 
192
    All memeory used for the child TABLE_LIST objects and the strings
 
193
    referred by it are taken from the parent TABLE::mem_root. Thus they
 
194
    are all freed implicitly at the final close of the table.
 
195
 
 
196
    TABLE::child_l -> TABLE_LIST::next_global -> TABLE_LIST::next_global
 
197
    #                 #               ^          #               ^
 
198
    #                 #               |          #               |
 
199
    #                 #               +--------- TABLE_LIST::prev_global
 
200
    #                 #                                          |
 
201
    #           |<--- TABLE_LIST::prev_global                    |
 
202
    #                                                            |
 
203
    TABLE::child_last_l -----------------------------------------+
 
204
 
 
205
  @param[in]    callback_param  data pointer as given to myrg_parent_open()
 
206
  @param[in]    filename        file name of MyISAM table
 
207
                                without extension.
 
208
 
 
209
  @return status
 
210
    @retval     0               OK
 
211
    @retval     != 0            Error
 
212
*/
 
213
 
 
214
static int myisammrg_parent_open_callback(void *callback_param,
 
215
                                          const char *filename)
 
216
{
 
217
  ha_myisammrg  *ha_myrg;
 
218
  TABLE         *parent;
 
219
  TABLE_LIST    *child_l;
 
220
  const char    *db;
 
221
  const char    *table_name;
 
222
  size_t        dirlen;
 
223
  char          dir_path[FN_REFLEN];
 
224
  DBUG_ENTER("myisammrg_parent_open_callback");
 
225
 
 
226
  /* Extract child table name and database name from filename. */
 
227
  dirlen= dirname_length(filename);
 
228
  if (dirlen >= FN_REFLEN)
 
229
  {
 
230
    /* purecov: begin inspected */
 
231
    DBUG_PRINT("error", ("name too long: '%.64s'", filename));
 
232
    my_errno= ENAMETOOLONG;
 
233
    DBUG_RETURN(1);
 
234
    /* purecov: end */
 
235
  }
 
236
  table_name= filename + dirlen;
 
237
  dirlen--; /* Strip off trailing '/'. */
 
238
  memcpy(dir_path, filename, dirlen);
 
239
  dir_path[dirlen]= '\0';
 
240
  db= base_name(dir_path);
 
241
  dirlen-= db - dir_path; /* This is now the length of 'db'. */
 
242
  DBUG_PRINT("myrg", ("open: '%s'.'%s'", db, table_name));
 
243
 
 
244
  ha_myrg= (ha_myisammrg*) callback_param;
 
245
  parent= ha_myrg->table_ptr();
 
246
 
 
247
  /* Get a TABLE_LIST object. */
 
248
  if (!(child_l= (TABLE_LIST*) alloc_root(&parent->mem_root,
 
249
                                          sizeof(TABLE_LIST))))
 
250
  {
 
251
    /* purecov: begin inspected */
 
252
    DBUG_PRINT("error", ("my_malloc error: %d", my_errno));
 
253
    DBUG_RETURN(1);
 
254
    /* purecov: end */
 
255
  }
 
256
  bzero((char*) child_l, sizeof(TABLE_LIST));
 
257
 
 
258
  /* Set database (schema) name. */
 
259
  child_l->db_length= dirlen;
 
260
  child_l->db= strmake_root(&parent->mem_root, db, dirlen);
 
261
  /* Set table name. */
 
262
  child_l->table_name_length= strlen(table_name);
 
263
  child_l->table_name= strmake_root(&parent->mem_root, table_name,
 
264
                                    child_l->table_name_length);
 
265
  /* Convert to lowercase if required. */
 
266
  if (lower_case_table_names && child_l->table_name_length)
 
267
    child_l->table_name_length= my_casedn_str(files_charset_info,
 
268
                                              child_l->table_name);
 
269
  /* Set alias. */
 
270
  child_l->alias= child_l->table_name;
 
271
 
 
272
  /* Initialize table map to 'undefined'. */
 
273
  child_l->init_child_def_version();
 
274
 
 
275
  /* Link TABLE_LIST object into the parent list. */
 
276
  if (!parent->child_last_l)
 
277
  {
 
278
    /* Initialize parent->child_last_l when handling first child. */
 
279
    parent->child_last_l= &parent->child_l;
 
280
  }
 
281
  *parent->child_last_l= child_l;
 
282
  child_l->prev_global= parent->child_last_l;
 
283
  parent->child_last_l= &child_l->next_global;
 
284
 
 
285
  DBUG_RETURN(0);
 
286
}
 
287
 
 
288
 
 
289
/**
 
290
  @brief Callback function for attaching a MERGE child table.
 
291
 
 
292
  @detail This function retrieves the MyISAM table handle from the
 
293
    next child table. It is called for each child table.
 
294
 
 
295
  @param[in]    callback_param      data pointer as given to
 
296
                                    myrg_attach_children()
 
297
 
 
298
  @return       pointer to open MyISAM table structure
 
299
    @retval     !=NULL                  OK, returning pointer
 
300
    @retval     NULL, my_errno == 0     Ok, no more child tables
 
301
    @retval     NULL, my_errno != 0     error
 
302
*/
 
303
 
 
304
static MI_INFO *myisammrg_attach_children_callback(void *callback_param)
 
305
{
 
306
  ha_myisammrg  *ha_myrg;
 
307
  TABLE         *parent;
 
308
  TABLE         *child;
 
309
  TABLE_LIST    *child_l;
 
310
  MI_INFO       *myisam;
 
311
  DBUG_ENTER("myisammrg_attach_children_callback");
 
312
 
 
313
  my_errno= 0;
 
314
  ha_myrg= (ha_myisammrg*) callback_param;
 
315
  parent= ha_myrg->table_ptr();
 
316
 
 
317
  /* Get child list item. */
 
318
  child_l= ha_myrg->next_child_attach;
 
319
  if (!child_l)
 
320
  {
 
321
    DBUG_PRINT("myrg", ("No more children to attach"));
 
322
    DBUG_RETURN(NULL);
 
323
  }
 
324
  child= child_l->table;
 
325
  DBUG_PRINT("myrg", ("child table: '%s'.'%s' 0x%lx", child->s->db.str,
 
326
                      child->s->table_name.str, (long) child));
 
327
  /*
 
328
    Prepare for next child. Used as child_l in next call to this function.
 
329
    We cannot rely on a NULL-terminated chain.
 
330
  */
 
331
  if (&child_l->next_global == parent->child_last_l)
 
332
  {
 
333
    DBUG_PRINT("myrg", ("attaching last child"));
 
334
    ha_myrg->next_child_attach= NULL;
 
335
  }
 
336
  else
 
337
    ha_myrg->next_child_attach= child_l->next_global;
 
338
 
 
339
  /* Set parent reference. */
 
340
  child->parent= parent;
 
341
 
 
342
  /*
 
343
    Do a quick compatibility check. The table def version is set when
 
344
    the table share is created. The child def version is copied
 
345
    from the table def version after a sucessful compatibility check.
 
346
    We need to repeat the compatibility check only if a child is opened
 
347
    from a different share than last time it was used with this MERGE
 
348
    table.
 
349
  */
 
350
  DBUG_PRINT("myrg", ("table_def_version last: %lu  current: %lu",
 
351
                      (ulong) child_l->get_child_def_version(),
 
352
                      (ulong) child->s->get_table_def_version()));
 
353
  if (child_l->get_child_def_version() != child->s->get_table_def_version())
 
354
    ha_myrg->need_compat_check= TRUE;
 
355
 
 
356
  /*
 
357
    If parent is temporary, children must be temporary too and vice
 
358
    versa. This check must be done for every child on every open because
 
359
    the table def version can overlap between temporary and
 
360
    non-temporary tables. We need to detect the case where a
 
361
    non-temporary table has been replaced with a temporary table of the
 
362
    same version. Or vice versa. A very unlikely case, but it could
 
363
    happen.
 
364
  */
 
365
  if (child->s->tmp_table != parent->s->tmp_table)
 
366
  {
 
367
    DBUG_PRINT("error", ("temporary table mismatch parent: %d  child: %d",
 
368
                         parent->s->tmp_table, child->s->tmp_table));
 
369
    my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
 
370
    goto err;
 
371
  }
 
372
 
 
373
  /* Extract the MyISAM table structure pointer from the handler object. */
 
374
  if ((child->file->ht->db_type != DB_TYPE_MYISAM) ||
 
375
      !(myisam= ((ha_myisam*) child->file)->file_ptr()))
 
376
  {
 
377
    DBUG_PRINT("error", ("no MyISAM handle for child table: '%s'.'%s' 0x%lx",
 
378
                         child->s->db.str, child->s->table_name.str,
 
379
                         (long) child));
 
380
    my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
 
381
  }
 
382
  DBUG_PRINT("myrg", ("MyISAM handle: 0x%lx  my_errno: %d",
 
383
                      my_errno ? NULL : (long) myisam, my_errno));
 
384
 
 
385
 err:
 
386
  DBUG_RETURN(my_errno ? NULL : myisam);
 
387
}
 
388
 
 
389
 
 
390
/**
 
391
  @brief Open a MERGE parent table, not its children.
 
392
 
 
393
  @detail This function initializes the MERGE storage engine structures
 
394
    and adds a child list of TABLE_LIST to the parent TABLE.
 
395
 
 
396
  @param[in]    name            MERGE table path name
 
397
  @param[in]    mode            read/write mode, unused
 
398
  @param[in]    test_if_locked  open flags
 
399
 
 
400
  @return       status
 
401
    @retval     0               OK
 
402
    @retval     -1              Error, my_errno gives reason
 
403
*/
 
404
 
 
405
int ha_myisammrg::open(const char *name, int mode __attribute__((unused)),
 
406
                       uint test_if_locked)
 
407
{
 
408
  DBUG_ENTER("ha_myisammrg::open");
 
409
  DBUG_PRINT("myrg", ("name: '%s'  table: 0x%lx", name, (long) table));
 
410
  DBUG_PRINT("myrg", ("test_if_locked: %u", test_if_locked));
 
411
 
 
412
  /* Save for later use. */
 
413
  this->test_if_locked= test_if_locked;
 
414
 
 
415
  /* retrieve children table list. */
 
416
  my_errno= 0;
 
417
  if (is_cloned)
 
418
  {
 
419
    /*
 
420
      Open and attaches the MyISAM tables,that are under the MERGE table 
 
421
      parent, on the MyISAM storage engine interface directly within the
 
422
      MERGE engine. The new MyISAM table instances, as well as the MERGE 
 
423
      clone itself, are not visible in the table cache. This is not a 
 
424
      problem because all locking is handled by the original MERGE table
 
425
      from which this is cloned of.
 
426
    */
 
427
    if (!(file= myrg_open(table->s->normalized_path.str, table->db_stat, 
 
428
                                       HA_OPEN_IGNORE_IF_LOCKED)))
 
429
    {
 
430
      DBUG_PRINT("error", ("my_errno %d", my_errno));
 
431
      DBUG_RETURN(my_errno ? my_errno : -1); 
 
432
    }
 
433
 
 
434
    file->children_attached= TRUE;
 
435
 
 
436
    info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
 
437
  }
 
438
  else if (!(file= myrg_parent_open(name, myisammrg_parent_open_callback, this)))
 
439
  {
 
440
    DBUG_PRINT("error", ("my_errno %d", my_errno));
 
441
    DBUG_RETURN(my_errno ? my_errno : -1);
 
442
  }
 
443
  DBUG_PRINT("myrg", ("MYRG_INFO: 0x%lx", (long) file));
 
444
  DBUG_RETURN(0);
 
445
}
 
446
 
 
447
/**
 
448
   Returns a cloned instance of the current handler.
 
449
 
 
450
   @return A cloned handler instance.
 
451
 */
 
452
handler *ha_myisammrg::clone(MEM_ROOT *mem_root)
 
453
{
 
454
  MYRG_TABLE    *u_table,*newu_table;
 
455
  ha_myisammrg *new_handler= 
 
456
    (ha_myisammrg*) get_new_handler(table->s, mem_root, table->s->db_type());
 
457
  if (!new_handler)
 
458
    return NULL;
 
459
  
 
460
  /* Inform ha_myisammrg::open() that it is a cloned handler */
 
461
  new_handler->is_cloned= TRUE;
 
462
  /*
 
463
    Allocate handler->ref here because otherwise ha_open will allocate it
 
464
    on this->table->mem_root and we will not be able to reclaim that memory 
 
465
    when the clone handler object is destroyed.
 
466
  */
 
467
  if (!(new_handler->ref= (uchar*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2)))
 
468
  {
 
469
    delete new_handler;
 
470
    return NULL;
 
471
  }
 
472
 
 
473
  if (new_handler->ha_open(table, table->s->normalized_path.str, table->db_stat,
 
474
                            HA_OPEN_IGNORE_IF_LOCKED))
 
475
  {
 
476
    delete new_handler;
 
477
    return NULL;
 
478
  }
 
479
 
 
480
  /*
 
481
    Iterate through the original child tables and
 
482
    copy the state into the cloned child tables.
 
483
    We need to do this because all the child tables
 
484
    can be involved in delete.
 
485
  */
 
486
  newu_table= new_handler->file->open_tables;
 
487
  for (u_table= file->open_tables; u_table < file->end_table; u_table++)
 
488
  {
 
489
    newu_table->table->state= u_table->table->state;
 
490
    newu_table++;
 
491
  }
 
492
 
 
493
  return new_handler;
 
494
 }
 
495
 
 
496
 
 
497
/**
 
498
  @brief Attach children to a MERGE table.
 
499
 
 
500
  @detail Let the storage engine attach its children through a callback
 
501
    function. Check table definitions for consistency.
 
502
 
 
503
  @note Special thd->open_options may be in effect. We can make use of
 
504
    them in attach. I.e. we use HA_OPEN_FOR_REPAIR to report the names
 
505
    of mismatching child tables. We cannot transport these options in
 
506
    ha_myisammrg::test_if_locked because they may change after the
 
507
    parent is opened. The parent is kept open in the table cache over
 
508
    multiple statements and can be used by other threads. Open options
 
509
    can change over time.
 
510
 
 
511
  @return status
 
512
    @retval     0               OK
 
513
    @retval     != 0            Error, my_errno gives reason
 
514
*/
 
515
 
 
516
int ha_myisammrg::attach_children(void)
 
517
{
 
518
  MYRG_TABLE    *u_table;
 
519
  MI_COLUMNDEF  *recinfo;
 
520
  MI_KEYDEF     *keyinfo;
 
521
  uint          recs;
 
522
  uint          keys= table->s->keys;
 
523
  int           error;
 
524
  DBUG_ENTER("ha_myisammrg::attach_children");
 
525
  DBUG_PRINT("myrg", ("table: '%s'.'%s' 0x%lx", table->s->db.str,
 
526
                      table->s->table_name.str, (long) table));
 
527
  DBUG_PRINT("myrg", ("test_if_locked: %u", this->test_if_locked));
 
528
  DBUG_ASSERT(!this->file->children_attached);
 
529
 
 
530
  /*
 
531
    Initialize variables that are used, modified, and/or set by
 
532
    myisammrg_attach_children_callback().
 
533
    'next_child_attach' traverses the chain of TABLE_LIST objects
 
534
    that has been compiled during myrg_parent_open(). Every call
 
535
    to myisammrg_attach_children_callback() moves the pointer to
 
536
    the next object.
 
537
    'need_compat_check' is set by myisammrg_attach_children_callback()
 
538
    if a child fails the table def version check.
 
539
    'my_errno' is set by myisammrg_attach_children_callback() in
 
540
    case of an error.
 
541
  */
 
542
  next_child_attach= table->child_l;
 
543
  need_compat_check= FALSE;
 
544
  my_errno= 0;
 
545
 
 
546
  if (myrg_attach_children(this->file, this->test_if_locked |
 
547
                           current_thd->open_options,
 
548
                           myisammrg_attach_children_callback, this,
 
549
                           (my_bool *) &need_compat_check))
 
550
  {
 
551
    DBUG_PRINT("error", ("my_errno %d", my_errno));
 
552
    DBUG_RETURN(my_errno ? my_errno : -1);
 
553
  }
 
554
  DBUG_PRINT("myrg", ("calling myrg_extrafunc"));
 
555
  myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref);
 
556
  if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
 
557
        test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
 
558
    myrg_extra(file,HA_EXTRA_NO_WAIT_LOCK,0);
 
559
  info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
 
560
  if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
 
561
    myrg_extra(file,HA_EXTRA_WAIT_LOCK,0);
 
562
 
 
563
  /*
 
564
    The compatibility check is required only if one or more children do
 
565
    not match their table def version from the last check. This will
 
566
    always happen at the first attach because the reference child def
 
567
    version is initialized to 'undefined' at open.
 
568
  */
 
569
  DBUG_PRINT("myrg", ("need_compat_check: %d", need_compat_check));
 
570
  if (need_compat_check)
 
571
  {
 
572
    TABLE_LIST *child_l;
 
573
 
 
574
    if (table->s->reclength != stats.mean_rec_length && stats.mean_rec_length)
 
575
    {
 
576
      DBUG_PRINT("error",("reclength: %lu  mean_rec_length: %lu",
 
577
                          table->s->reclength, stats.mean_rec_length));
 
578
      if (test_if_locked & HA_OPEN_FOR_REPAIR)
 
579
        myrg_print_wrong_table(file->open_tables->table->filename);
 
580
      error= HA_ERR_WRONG_MRG_TABLE_DEF;
 
581
      goto err;
 
582
    }
 
583
    /*
 
584
      Both recinfo and keyinfo are allocated by my_multi_malloc(), thus
 
585
      only recinfo must be freed.
 
586
    */
 
587
    if ((error= table2myisam(table, &keyinfo, &recinfo, &recs)))
 
588
    {
 
589
      /* purecov: begin inspected */
 
590
      DBUG_PRINT("error", ("failed to convert TABLE object to MyISAM "
 
591
                           "key and column definition"));
 
592
      goto err;
 
593
      /* purecov: end */
 
594
    }
 
595
    for (u_table= file->open_tables; u_table < file->end_table; u_table++)
 
596
    {
 
597
      if (check_definition(keyinfo, recinfo, keys, recs,
 
598
                           u_table->table->s->keyinfo, u_table->table->s->rec,
 
599
                           u_table->table->s->base.keys,
 
600
                           u_table->table->s->base.fields, false, NULL))
 
601
      {
 
602
        DBUG_PRINT("error", ("table definition mismatch: '%s'",
 
603
                             u_table->table->filename));
 
604
        error= HA_ERR_WRONG_MRG_TABLE_DEF;
 
605
        if (!(this->test_if_locked & HA_OPEN_FOR_REPAIR))
 
606
        {
 
607
          my_free((uchar*) recinfo, MYF(0));
 
608
          goto err;
 
609
        }
 
610
        myrg_print_wrong_table(u_table->table->filename);
 
611
      }
 
612
    }
 
613
    my_free((uchar*) recinfo, MYF(0));
 
614
    if (error == HA_ERR_WRONG_MRG_TABLE_DEF)
 
615
      goto err;
 
616
 
 
617
    /* All checks passed so far. Now update child def version. */
 
618
    for (child_l= table->child_l; ; child_l= child_l->next_global)
 
619
    {
 
620
      child_l->set_child_def_version(
 
621
        child_l->table->s->get_table_def_version());
 
622
 
 
623
      if (&child_l->next_global == table->child_last_l)
 
624
        break;
 
625
    }
 
626
  }
 
627
#if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4
 
628
  /* Merge table has more than 2G rows */
 
629
  if (table->s->crashed)
 
630
  {
 
631
    DBUG_PRINT("error", ("MERGE table marked crashed"));
 
632
    error= HA_ERR_WRONG_MRG_TABLE_DEF;
 
633
    goto err;
 
634
  }
 
635
#endif
 
636
  DBUG_RETURN(0);
 
637
 
 
638
err:
 
639
  myrg_detach_children(file);
 
640
  DBUG_RETURN(my_errno= error);
 
641
}
 
642
 
 
643
 
 
644
/**
 
645
  @brief Detach all children from a MERGE table.
 
646
 
 
647
  @note Detach must not touch the children in any way.
 
648
    They may have been closed at ths point already.
 
649
    All references to the children should be removed.
 
650
 
 
651
  @return status
 
652
    @retval     0               OK
 
653
    @retval     != 0            Error, my_errno gives reason
 
654
*/
 
655
 
 
656
int ha_myisammrg::detach_children(void)
 
657
{
 
658
  DBUG_ENTER("ha_myisammrg::detach_children");
 
659
  DBUG_ASSERT(this->file && this->file->children_attached);
 
660
 
 
661
  if (myrg_detach_children(this->file))
 
662
  {
 
663
    /* purecov: begin inspected */
 
664
    DBUG_PRINT("error", ("my_errno %d", my_errno));
 
665
    DBUG_RETURN(my_errno ? my_errno : -1);
 
666
    /* purecov: end */
 
667
  }
 
668
  DBUG_RETURN(0);
 
669
}
 
670
 
 
671
 
 
672
/**
 
673
  @brief Close a MERGE parent table, not its children.
 
674
 
 
675
  @note The children are expected to be closed separately by the caller.
 
676
 
 
677
  @return status
 
678
    @retval     0               OK
 
679
    @retval     != 0            Error, my_errno gives reason
 
680
*/
 
681
 
 
682
int ha_myisammrg::close(void)
 
683
{
 
684
  int rc;
 
685
  DBUG_ENTER("ha_myisammrg::close");
 
686
  /*
 
687
    Children must not be attached here. Unless the MERGE table has no
 
688
    children or the handler instance has been cloned. In these cases 
 
689
    children_attached is always true. 
 
690
  */
 
691
  DBUG_ASSERT(!this->file->children_attached || !this->file->tables || this->is_cloned);
 
692
  rc= myrg_close(file);
 
693
  file= 0;
 
694
  DBUG_RETURN(rc);
 
695
}
 
696
 
 
697
int ha_myisammrg::write_row(uchar * buf)
 
698
{
 
699
  DBUG_ENTER("ha_myisammrg::write_row");
 
700
  DBUG_ASSERT(this->file->children_attached);
 
701
  ha_statistic_increment(&SSV::ha_write_count);
 
702
 
 
703
  if (file->merge_insert_method == MERGE_INSERT_DISABLED || !file->tables)
 
704
    DBUG_RETURN(HA_ERR_TABLE_READONLY);
 
705
 
 
706
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
 
707
    table->timestamp_field->set_time();
 
708
  if (table->next_number_field && buf == table->record[0])
 
709
  {
 
710
    int error;
 
711
    if ((error= update_auto_increment()))
 
712
      DBUG_RETURN(error); /* purecov: inspected */
 
713
  }
 
714
  DBUG_RETURN(myrg_write(file,buf));
 
715
}
 
716
 
 
717
int ha_myisammrg::update_row(const uchar * old_data, uchar * new_data)
 
718
{
 
719
  DBUG_ASSERT(this->file->children_attached);
 
720
  ha_statistic_increment(&SSV::ha_update_count);
 
721
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
 
722
    table->timestamp_field->set_time();
 
723
  return myrg_update(file,old_data,new_data);
 
724
}
 
725
 
 
726
int ha_myisammrg::delete_row(const uchar * buf)
 
727
{
 
728
  DBUG_ASSERT(this->file->children_attached);
 
729
  ha_statistic_increment(&SSV::ha_delete_count);
 
730
  return myrg_delete(file,buf);
 
731
}
 
732
 
 
733
int ha_myisammrg::index_read_map(uchar * buf, const uchar * key,
 
734
                                 key_part_map keypart_map,
 
735
                                 enum ha_rkey_function find_flag)
 
736
{
 
737
  DBUG_ASSERT(this->file->children_attached);
 
738
  ha_statistic_increment(&SSV::ha_read_key_count);
 
739
  int error=myrg_rkey(file,buf,active_index, key, keypart_map, find_flag);
 
740
  table->status=error ? STATUS_NOT_FOUND: 0;
 
741
  return error;
 
742
}
 
743
 
 
744
int ha_myisammrg::index_read_idx_map(uchar * buf, uint index, const uchar * key,
 
745
                                     key_part_map keypart_map,
 
746
                                     enum ha_rkey_function find_flag)
 
747
{
 
748
  DBUG_ASSERT(this->file->children_attached);
 
749
  ha_statistic_increment(&SSV::ha_read_key_count);
 
750
  int error=myrg_rkey(file,buf,index, key, keypart_map, find_flag);
 
751
  table->status=error ? STATUS_NOT_FOUND: 0;
 
752
  return error;
 
753
}
 
754
 
 
755
int ha_myisammrg::index_read_last_map(uchar *buf, const uchar *key,
 
756
                                      key_part_map keypart_map)
 
757
{
 
758
  DBUG_ASSERT(this->file->children_attached);
 
759
  ha_statistic_increment(&SSV::ha_read_key_count);
 
760
  int error=myrg_rkey(file,buf,active_index, key, keypart_map,
 
761
                      HA_READ_PREFIX_LAST);
 
762
  table->status=error ? STATUS_NOT_FOUND: 0;
 
763
  return error;
 
764
}
 
765
 
 
766
int ha_myisammrg::index_next(uchar * buf)
 
767
{
 
768
  DBUG_ASSERT(this->file->children_attached);
 
769
  ha_statistic_increment(&SSV::ha_read_next_count);
 
770
  int error=myrg_rnext(file,buf,active_index);
 
771
  table->status=error ? STATUS_NOT_FOUND: 0;
 
772
  return error;
 
773
}
 
774
 
 
775
int ha_myisammrg::index_prev(uchar * buf)
 
776
{
 
777
  DBUG_ASSERT(this->file->children_attached);
 
778
  ha_statistic_increment(&SSV::ha_read_prev_count);
 
779
  int error=myrg_rprev(file,buf, active_index);
 
780
  table->status=error ? STATUS_NOT_FOUND: 0;
 
781
  return error;
 
782
}
 
783
 
 
784
int ha_myisammrg::index_first(uchar * buf)
 
785
{
 
786
  DBUG_ASSERT(this->file->children_attached);
 
787
  ha_statistic_increment(&SSV::ha_read_first_count);
 
788
  int error=myrg_rfirst(file, buf, active_index);
 
789
  table->status=error ? STATUS_NOT_FOUND: 0;
 
790
  return error;
 
791
}
 
792
 
 
793
int ha_myisammrg::index_last(uchar * buf)
 
794
{
 
795
  DBUG_ASSERT(this->file->children_attached);
 
796
  ha_statistic_increment(&SSV::ha_read_last_count);
 
797
  int error=myrg_rlast(file, buf, active_index);
 
798
  table->status=error ? STATUS_NOT_FOUND: 0;
 
799
  return error;
 
800
}
 
801
 
 
802
int ha_myisammrg::index_next_same(uchar * buf,
 
803
                                  const uchar *key __attribute__((unused)),
 
804
                                  uint length __attribute__((unused)))
 
805
{
 
806
  int error;
 
807
  DBUG_ASSERT(this->file->children_attached);
 
808
  ha_statistic_increment(&SSV::ha_read_next_count);
 
809
  do
 
810
  {
 
811
    error= myrg_rnext_same(file,buf);
 
812
  } while (error == HA_ERR_RECORD_DELETED);
 
813
  table->status=error ? STATUS_NOT_FOUND: 0;
 
814
  return error;
 
815
}
 
816
 
 
817
 
 
818
int ha_myisammrg::rnd_init(bool scan)
 
819
{
 
820
  DBUG_ASSERT(this->file->children_attached);
 
821
  return myrg_reset(file);
 
822
}
 
823
 
 
824
 
 
825
int ha_myisammrg::rnd_next(uchar *buf)
 
826
{
 
827
  DBUG_ASSERT(this->file->children_attached);
 
828
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
 
829
  int error=myrg_rrnd(file, buf, HA_OFFSET_ERROR);
 
830
  table->status=error ? STATUS_NOT_FOUND: 0;
 
831
  return error;
 
832
}
 
833
 
 
834
 
 
835
int ha_myisammrg::rnd_pos(uchar * buf, uchar *pos)
 
836
{
 
837
  DBUG_ASSERT(this->file->children_attached);
 
838
  ha_statistic_increment(&SSV::ha_read_rnd_count);
 
839
  int error=myrg_rrnd(file, buf, my_get_ptr(pos,ref_length));
 
840
  table->status=error ? STATUS_NOT_FOUND: 0;
 
841
  return error;
 
842
}
 
843
 
 
844
void ha_myisammrg::position(const uchar *record)
 
845
{
 
846
  DBUG_ASSERT(this->file->children_attached);
 
847
  ulonglong row_position= myrg_position(file);
 
848
  my_store_ptr(ref, ref_length, (my_off_t) row_position);
 
849
}
 
850
 
 
851
 
 
852
ha_rows ha_myisammrg::records_in_range(uint inx, key_range *min_key,
 
853
                                       key_range *max_key)
 
854
{
 
855
  DBUG_ASSERT(this->file->children_attached);
 
856
  return (ha_rows) myrg_records_in_range(file, (int) inx, min_key, max_key);
 
857
}
 
858
 
 
859
 
 
860
int ha_myisammrg::info(uint flag)
 
861
{
 
862
  MYMERGE_INFO mrg_info;
 
863
  DBUG_ASSERT(this->file->children_attached);
 
864
  (void) myrg_status(file,&mrg_info,flag);
 
865
  /*
 
866
    The following fails if one has not compiled MySQL with -DBIG_TABLES
 
867
    and one has more than 2^32 rows in the merge tables.
 
868
  */
 
869
  stats.records = (ha_rows) mrg_info.records;
 
870
  stats.deleted = (ha_rows) mrg_info.deleted;
 
871
#if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4
 
872
  if ((mrg_info.records >= (ulonglong) 1 << 32) ||
 
873
      (mrg_info.deleted >= (ulonglong) 1 << 32))
 
874
    table->s->crashed= 1;
 
875
#endif
 
876
  stats.data_file_length= mrg_info.data_file_length;
 
877
  if (mrg_info.errkey >= (int) table_share->keys)
 
878
  {
 
879
    /*
 
880
     If value of errkey is higher than the number of keys
 
881
     on the table set errkey to MAX_KEY. This will be
 
882
     treated as unknown key case and error message generator
 
883
     won't try to locate key causing segmentation fault.
 
884
    */
 
885
    mrg_info.errkey= MAX_KEY;
 
886
  }
 
887
  table->s->keys_in_use.set_prefix(table->s->keys);
 
888
  stats.mean_rec_length= mrg_info.reclength;
 
889
  
 
890
  /* 
 
891
    The handler::block_size is used all over the code in index scan cost
 
892
    calculations. It is used to get number of disk seeks required to
 
893
    retrieve a number of index tuples.
 
894
    If the merge table has N underlying tables, then (assuming underlying
 
895
    tables have equal size, the only "simple" approach we can use)
 
896
    retrieving X index records from a merge table will require N times more
 
897
    disk seeks compared to doing the same on a MyISAM table with equal
 
898
    number of records.
 
899
    In the edge case (file_tables > myisam_block_size) we'll get
 
900
    block_size==0, and index calculation code will act as if we need one
 
901
    disk seek to retrieve one index tuple.
 
902
 
 
903
    TODO: In 5.2 index scan cost calculation will be factored out into a
 
904
    virtual function in class handler and we'll be able to remove this hack.
 
905
  */
 
906
  stats.block_size= 0;
 
907
  if (file->tables)
 
908
    stats.block_size= myisam_block_size / file->tables;
 
909
  
 
910
  stats.update_time= 0;
 
911
#if SIZEOF_OFF_T > 4
 
912
  ref_length=6;                                 // Should be big enough
 
913
#else
 
914
  ref_length=4;                                 // Can't be > than my_off_t
 
915
#endif
 
916
  if (flag & HA_STATUS_CONST)
 
917
  {
 
918
    if (table->s->key_parts && mrg_info.rec_per_key)
 
919
    {
 
920
#ifdef HAVE_purify
 
921
      /*
 
922
        valgrind may be unhappy about it, because optimizer may access values
 
923
        between file->keys and table->key_parts, that will be uninitialized.
 
924
        It's safe though, because even if opimizer will decide to use a key
 
925
        with such a number, it'll be an error later anyway.
 
926
      */
 
927
      bzero((char*) table->key_info[0].rec_per_key,
 
928
            sizeof(table->key_info[0].rec_per_key[0]) * table->s->key_parts);
 
929
#endif
 
930
      memcpy((char*) table->key_info[0].rec_per_key,
 
931
             (char*) mrg_info.rec_per_key,
 
932
             sizeof(table->key_info[0].rec_per_key[0]) *
 
933
             min(file->keys, table->s->key_parts));
 
934
    }
 
935
  }
 
936
  if (flag & HA_STATUS_ERRKEY)
 
937
  {
 
938
    errkey= mrg_info.errkey;
 
939
    my_store_ptr(dup_ref, ref_length, mrg_info.dupp_key_pos);
 
940
  }
 
941
  return 0;
 
942
}
 
943
 
 
944
 
 
945
int ha_myisammrg::extra(enum ha_extra_function operation)
 
946
{
 
947
  if (operation == HA_EXTRA_ATTACH_CHILDREN)
 
948
  {
 
949
    int rc= attach_children();
 
950
    if (!rc)
 
951
      (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
 
952
    return(rc);
 
953
  }
 
954
  else if (operation == HA_EXTRA_DETACH_CHILDREN)
 
955
  {
 
956
    /*
 
957
      Note that detach must not touch the children in any way.
 
958
      They may have been closed at ths point already.
 
959
    */
 
960
    int rc= detach_children();
 
961
    return(rc);
 
962
  }
 
963
 
 
964
  /* As this is just a mapping, we don't have to force the underlying
 
965
     tables to be closed */
 
966
  if (operation == HA_EXTRA_FORCE_REOPEN ||
 
967
      operation == HA_EXTRA_PREPARE_FOR_DROP)
 
968
    return 0;
 
969
  return myrg_extra(file,operation,0);
 
970
}
 
971
 
 
972
int ha_myisammrg::reset(void)
 
973
{
 
974
  return myrg_reset(file);
 
975
}
 
976
 
 
977
/* To be used with WRITE_CACHE, EXTRA_CACHE and BULK_INSERT_BEGIN */
 
978
 
 
979
int ha_myisammrg::extra_opt(enum ha_extra_function operation, ulong cache_size)
 
980
{
 
981
  DBUG_ASSERT(this->file->children_attached);
 
982
  if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE)
 
983
    return 0;
 
984
  return myrg_extra(file, operation, (void*) &cache_size);
 
985
}
 
986
 
 
987
int ha_myisammrg::external_lock(THD *thd, int lock_type)
 
988
{
 
989
  DBUG_ASSERT(this->file->children_attached);
 
990
  return myrg_lock_database(file,lock_type);
 
991
}
 
992
 
 
993
uint ha_myisammrg::lock_count(void) const
 
994
{
 
995
  /*
 
996
    Return the real lock count even if the children are not attached.
 
997
    This method is used for allocating memory. If we would return 0
 
998
    to another thread (e.g. doing FLUSH TABLE), and attach the children
 
999
    before the other thread calls store_lock(), then we would return
 
1000
    more locks in store_lock() than we claimed by lock_count(). The
 
1001
    other tread would overrun its memory.
 
1002
  */
 
1003
  return file->tables;
 
1004
}
 
1005
 
 
1006
 
 
1007
THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd,
 
1008
                                         THR_LOCK_DATA **to,
 
1009
                                         enum thr_lock_type lock_type)
 
1010
{
 
1011
  MYRG_TABLE *open_table;
 
1012
 
 
1013
  /*
 
1014
    This method can be called while another thread is attaching the
 
1015
    children. If the processor reorders instructions or write to memory,
 
1016
    'children_attached' could be set before 'open_tables' has all the
 
1017
    pointers to the children. Use of a mutex here and in
 
1018
    myrg_attach_children() forces consistent data.
 
1019
  */
 
1020
  pthread_mutex_lock(&this->file->mutex);
 
1021
 
 
1022
  /*
 
1023
    When MERGE table is open, but not yet attached, other threads
 
1024
    could flush it, which means call mysql_lock_abort_for_thread()
 
1025
    on this threads TABLE. 'children_attached' is FALSE in this
 
1026
    situaton. Since the table is not locked, return no lock data.
 
1027
  */
 
1028
  if (!this->file->children_attached)
 
1029
    goto end; /* purecov: tested */
 
1030
 
 
1031
  for (open_table=file->open_tables ;
 
1032
       open_table != file->end_table ;
 
1033
       open_table++)
 
1034
  {
 
1035
    *(to++)= &open_table->table->lock;
 
1036
    if (lock_type != TL_IGNORE && open_table->table->lock.type == TL_UNLOCK)
 
1037
      open_table->table->lock.type=lock_type;
 
1038
  }
 
1039
 
 
1040
 end:
 
1041
  pthread_mutex_unlock(&this->file->mutex);
 
1042
  return to;
 
1043
}
 
1044
 
 
1045
 
 
1046
/* Find out database name and table name from a filename */
 
1047
 
 
1048
static void split_file_name(const char *file_name,
 
1049
                            LEX_STRING *db, LEX_STRING *name)
 
1050
{
 
1051
  size_t dir_length, prefix_length;
 
1052
  char buff[FN_REFLEN];
 
1053
 
 
1054
  db->length= 0;
 
1055
  strmake(buff, file_name, sizeof(buff)-1);
 
1056
  dir_length= dirname_length(buff);
 
1057
  if (dir_length > 1)
 
1058
  {
 
1059
    /* Get database */
 
1060
    buff[dir_length-1]= 0;                      // Remove end '/'
 
1061
    prefix_length= dirname_length(buff);
 
1062
    db->str= (char*) file_name+ prefix_length;
 
1063
    db->length= dir_length - prefix_length -1;
 
1064
  }
 
1065
  name->str= (char*) file_name+ dir_length;
 
1066
  name->length= (uint) (fn_ext(name->str) - name->str);
 
1067
}
 
1068
 
 
1069
 
 
1070
void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info)
 
1071
{
 
1072
  DBUG_ENTER("ha_myisammrg::update_create_info");
 
1073
 
 
1074
  if (!(create_info->used_fields & HA_CREATE_USED_UNION))
 
1075
  {
 
1076
    MYRG_TABLE *open_table;
 
1077
    THD *thd=current_thd;
 
1078
 
 
1079
    create_info->merge_list.next= &create_info->merge_list.first;
 
1080
    create_info->merge_list.elements=0;
 
1081
 
 
1082
    for (open_table=file->open_tables ;
 
1083
         open_table != file->end_table ;
 
1084
         open_table++)
 
1085
    {
 
1086
      TABLE_LIST *ptr;
 
1087
      LEX_STRING db, name;
 
1088
      LINT_INIT(db.str);
 
1089
 
 
1090
      if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
 
1091
        goto err;
 
1092
      split_file_name(open_table->table->filename, &db, &name);
 
1093
      if (!(ptr->table_name= thd->strmake(name.str, name.length)))
 
1094
        goto err;
 
1095
      if (db.length && !(ptr->db= thd->strmake(db.str, db.length)))
 
1096
        goto err;
 
1097
 
 
1098
      create_info->merge_list.elements++;
 
1099
      (*create_info->merge_list.next) = (uchar*) ptr;
 
1100
      create_info->merge_list.next= (uchar**) &ptr->next_local;
 
1101
    }
 
1102
    *create_info->merge_list.next=0;
 
1103
  }
 
1104
  if (!(create_info->used_fields & HA_CREATE_USED_INSERT_METHOD))
 
1105
  {
 
1106
    create_info->merge_insert_method = file->merge_insert_method;
 
1107
  }
 
1108
  DBUG_VOID_RETURN;
 
1109
 
 
1110
err:
 
1111
  create_info->merge_list.elements=0;
 
1112
  create_info->merge_list.first=0;
 
1113
  DBUG_VOID_RETURN;
 
1114
}
 
1115
 
 
1116
 
 
1117
int ha_myisammrg::create(const char *name, register TABLE *form,
 
1118
                         HA_CREATE_INFO *create_info)
 
1119
{
 
1120
  char buff[FN_REFLEN];
 
1121
  const char **table_names, **pos;
 
1122
  TABLE_LIST *tables= (TABLE_LIST*) create_info->merge_list.first;
 
1123
  THD *thd= current_thd;
 
1124
  size_t dirlgt= dirname_length(name);
 
1125
  DBUG_ENTER("ha_myisammrg::create");
 
1126
 
 
1127
  /* Allocate a table_names array in thread mem_root. */
 
1128
  if (!(table_names= (const char**)
 
1129
        thd->alloc((create_info->merge_list.elements+1) * sizeof(char*))))
 
1130
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
 
1131
 
 
1132
  /* Create child path names. */
 
1133
  for (pos= table_names; tables; tables= tables->next_local)
 
1134
  {
 
1135
    const char *table_name;
 
1136
 
 
1137
    /*
 
1138
      Construct the path to the MyISAM table. Try to meet two conditions:
 
1139
      1.) Allow to include MyISAM tables from different databases, and
 
1140
      2.) allow for moving DATADIR around in the file system.
 
1141
      The first means that we need paths in the .MRG file. The second
 
1142
      means that we should not have absolute paths in the .MRG file.
 
1143
      The best, we can do, is to use 'mysql_data_home', which is '.'
 
1144
      in mysqld and may be an absolute path in an embedded server.
 
1145
      This means that it might not be possible to move the DATADIR of
 
1146
      an embedded server without changing the paths in the .MRG file.
 
1147
 
 
1148
      Do the same even for temporary tables. MERGE children are now
 
1149
      opened through the table cache. They are opened by db.table_name,
 
1150
      not by their path name.
 
1151
    */
 
1152
    uint length= build_table_filename(buff, sizeof(buff),
 
1153
                                      tables->db, tables->table_name, "", 0);
 
1154
    /*
 
1155
      If a MyISAM table is in the same directory as the MERGE table,
 
1156
      we use the table name without a path. This means that the
 
1157
      DATADIR can easily be moved even for an embedded server as long
 
1158
      as the MyISAM tables are from the same database as the MERGE table.
 
1159
    */
 
1160
    if ((dirname_length(buff) == dirlgt) && ! memcmp(buff, name, dirlgt))
 
1161
      table_name= tables->table_name;
 
1162
    else
 
1163
      if (! (table_name= thd->strmake(buff, length)))
 
1164
        DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
 
1165
 
 
1166
    *pos++= table_name;
 
1167
  }
 
1168
  *pos=0;
 
1169
 
 
1170
  /* Create a MERGE meta file from the table_names array. */
 
1171
  DBUG_RETURN(myrg_create(fn_format(buff,name,"","",
 
1172
                                    MY_RESOLVE_SYMLINKS|
 
1173
                                    MY_UNPACK_FILENAME|MY_APPEND_EXT),
 
1174
                          table_names,
 
1175
                          create_info->merge_insert_method,
 
1176
                          (my_bool) 0));
 
1177
}
 
1178
 
 
1179
 
 
1180
void ha_myisammrg::append_create_info(String *packet)
 
1181
{
 
1182
  const char *current_db;
 
1183
  size_t db_length;
 
1184
  THD *thd= current_thd;
 
1185
  MYRG_TABLE *open_table, *first;
 
1186
 
 
1187
  if (file->merge_insert_method != MERGE_INSERT_DISABLED)
 
1188
  {
 
1189
    packet->append(STRING_WITH_LEN(" INSERT_METHOD="));
 
1190
    packet->append(get_type(&merge_insert_method,file->merge_insert_method-1));
 
1191
  }
 
1192
  /*
 
1193
    There is no sence adding UNION clause in case there is no underlying
 
1194
    tables specified.
 
1195
  */
 
1196
  if (file->open_tables == file->end_table)
 
1197
    return;
 
1198
  packet->append(STRING_WITH_LEN(" UNION=("));
 
1199
 
 
1200
  current_db= table->s->db.str;
 
1201
  db_length=  table->s->db.length;
 
1202
 
 
1203
  for (first=open_table=file->open_tables ;
 
1204
       open_table != file->end_table ;
 
1205
       open_table++)
 
1206
  {
 
1207
    LEX_STRING db, name;
 
1208
    LINT_INIT(db.str);
 
1209
 
 
1210
    split_file_name(open_table->table->filename, &db, &name);
 
1211
    if (open_table != first)
 
1212
      packet->append(',');
 
1213
    /* Report database for mapped table if it isn't in current database */
 
1214
    if (db.length &&
 
1215
        (db_length != db.length ||
 
1216
         strncmp(current_db, db.str, db.length)))
 
1217
    {
 
1218
      append_identifier(thd, packet, db.str, db.length);
 
1219
      packet->append('.');
 
1220
    }
 
1221
    append_identifier(thd, packet, name.str, name.length);
 
1222
  }
 
1223
  packet->append(')');
 
1224
}
 
1225
 
 
1226
 
 
1227
bool ha_myisammrg::check_if_incompatible_data(HA_CREATE_INFO *info,
 
1228
                                              uint table_changes)
 
1229
{
 
1230
  /*
 
1231
    For myisammrg, we should always re-generate the mapping file as this
 
1232
    is trivial to do
 
1233
  */
 
1234
  return COMPATIBLE_DATA_NO;
 
1235
}
 
1236
 
 
1237
 
 
1238
int ha_myisammrg::check(THD* thd, HA_CHECK_OPT* check_opt)
 
1239
{
 
1240
  return HA_ADMIN_OK;
 
1241
}
 
1242
 
 
1243
 
 
1244
ha_rows ha_myisammrg::records()
 
1245
{
 
1246
  return myrg_records(file);
 
1247
}
 
1248
 
 
1249
 
 
1250
extern int myrg_panic(enum ha_panic_function flag);
 
1251
int myisammrg_panic(handlerton *hton, ha_panic_function flag)
 
1252
{
 
1253
  return myrg_panic(flag);
 
1254
}
 
1255
 
 
1256
static int myisammrg_init(void *p)
 
1257
{
 
1258
  handlerton *myisammrg_hton;
 
1259
 
 
1260
  myisammrg_hton= (handlerton *)p;
 
1261
 
 
1262
  myisammrg_hton->db_type= DB_TYPE_MRG_MYISAM;
 
1263
  myisammrg_hton->create= myisammrg_create_handler;
 
1264
  myisammrg_hton->panic= myisammrg_panic;
 
1265
  myisammrg_hton->flags= HTON_NO_PARTITION;
 
1266
 
 
1267
  return 0;
 
1268
}
 
1269
 
 
1270
struct st_mysql_storage_engine myisammrg_storage_engine=
 
1271
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
 
1272
 
 
1273
mysql_declare_plugin(myisammrg)
 
1274
{
 
1275
  MYSQL_STORAGE_ENGINE_PLUGIN,
 
1276
  &myisammrg_storage_engine,
 
1277
  "MRG_MYISAM",
 
1278
  "MySQL AB",
 
1279
  "Collection of identical MyISAM tables",
 
1280
  PLUGIN_LICENSE_GPL,
 
1281
  myisammrg_init, /* Plugin Init */
 
1282
  NULL, /* Plugin Deinit */
 
1283
  0x0100, /* 1.0 */
 
1284
  NULL,                       /* status variables                */
 
1285
  NULL,                       /* system variables                */
 
1286
  NULL                        /* config options                  */
 
1287
}
 
1288
mysql_declare_plugin_end;