mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / myisammrg / ha_myisammrg.cc
blob75c96a3527e78516d556343142cffc8d07fe920e
1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 MyISAM MERGE tables
21 A MyISAM MERGE table is kind of a union of zero or more MyISAM tables.
23 Besides the normal form file (.frm) a MERGE table has a meta file
24 (.MRG) with a list of tables. These are paths to the MyISAM table
25 files. The last two components of the path contain the database name
26 and the table name respectively.
28 When a MERGE table is open, there exists an TABLE object for the MERGE
29 table itself and a TABLE object for each of the MyISAM tables. For
30 abbreviated writing, I call the MERGE table object "parent" and the
31 MyISAM table objects "children".
33 A MERGE table is almost always opened through open_and_lock_tables()
34 and hence through open_tables(). When the parent appears in the list
35 of tables to open, the initial open of the handler does nothing but
36 read the meta file and collect a list of TABLE_LIST objects for the
37 children. This list is attached to the parent TABLE object as
38 TABLE::child_l. The end of the children list is saved in
39 TABLE::child_last_l.
41 Back in open_tables(), add_merge_table_list() is called. It updates
42 each list member with the lock type and a back pointer to the parent
43 TABLE_LIST object TABLE_LIST::parent_l. The list is then inserted in
44 the list of tables to open, right behind the parent. Consequently,
45 open_tables() opens the children, one after the other. The TABLE
46 references of the TABLE_LIST objects are implicitly set to the open
47 tables. The children are opened as independent MyISAM tables, right as
48 if they are used by the SQL statement.
50 TABLE_LIST::parent_l is required to find the parent 1. when the last
51 child has been opened and children are to be attached, and 2. when an
52 error happens during child open and the child list must be removed
53 from the queuery list. In these cases the current child does not have
54 TABLE::parent set or does not have a TABLE at all respectively.
56 When the last child is open, attach_merge_children() is called. It
57 removes the list of children from the open list. Then the children are
58 "attached" to the parent. All required references between parent and
59 children are set up.
61 The MERGE storage engine sets up an array with references to the
62 low-level MyISAM table objects (MI_INFO). It remembers the state of
63 the table in MYRG_INFO::children_attached.
65 Every child TABLE::parent references the parent TABLE object. That way
66 TABLE objects belonging to a MERGE table can be identified.
67 TABLE::parent is required because the parent and child TABLE objects
68 can live longer than the parent TABLE_LIST object. So the path
69 child->pos_in_table_list->parent_l->table can be broken.
71 If necessary, the compatibility of parent and children is checked.
72 This check is necessary when any of the objects are reopend. This is
73 detected by comparing the current table def version against the
74 remembered child def version. On parent open, the list members are
75 initialized to an "impossible"/"undefined" version value. So the check
76 is always executed on the first attach.
78 The version check is done in myisammrg_attach_children_callback(),
79 which is called for every child. ha_myisammrg::attach_children()
80 initializes 'need_compat_check' to FALSE and
81 myisammrg_attach_children_callback() sets it ot TRUE if a table
82 def version mismatches the remembered child def version.
84 Finally the parent TABLE::children_attached is set.
86 ---
88 On parent open the storage engine structures are allocated and initialized.
89 They stay with the open table until its final close.
94 #ifdef USE_PRAGMA_IMPLEMENTATION
95 #pragma implementation // gcc: Class implementation
96 #endif
98 #define MYSQL_SERVER 1
99 #include "mysql_priv.h"
100 #include <mysql/plugin.h>
101 #include <m_ctype.h>
102 #include "../myisam/ha_myisam.h"
103 #include "ha_myisammrg.h"
104 #include "myrg_def.h"
107 static handler *myisammrg_create_handler(handlerton *hton,
108 TABLE_SHARE *table,
109 MEM_ROOT *mem_root)
111 return new (mem_root) ha_myisammrg(hton, table);
116 @brief Constructor
119 ha_myisammrg::ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg)
120 :handler(hton, table_arg), file(0), is_cloned(0)
125 @brief Destructor
128 ha_myisammrg::~ha_myisammrg(void)
132 static const char *ha_myisammrg_exts[] = {
133 ".MRG",
134 NullS
136 extern int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
137 MI_COLUMNDEF **recinfo_out, uint *records_out);
138 extern int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
139 uint t1_keys, uint t1_recs,
140 MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
141 uint t2_keys, uint t2_recs, bool strict,
142 TABLE *table_arg);
143 static void split_file_name(const char *file_name,
144 LEX_STRING *db, LEX_STRING *name);
147 extern "C" void myrg_print_wrong_table(const char *table_name)
149 LEX_STRING db= {NULL, 0}, name;
150 char buf[FN_REFLEN];
151 split_file_name(table_name, &db, &name);
152 memcpy(buf, db.str, db.length);
153 buf[db.length]= '.';
154 memcpy(buf + db.length + 1, name.str, name.length);
155 buf[db.length + name.length + 1]= 0;
156 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
157 ER_ADMIN_WRONG_MRG_TABLE, ER(ER_ADMIN_WRONG_MRG_TABLE),
158 buf);
162 const char **ha_myisammrg::bas_ext() const
164 return ha_myisammrg_exts;
168 const char *ha_myisammrg::index_type(uint key_number)
170 return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
171 "FULLTEXT" :
172 (table->key_info[key_number].flags & HA_SPATIAL) ?
173 "SPATIAL" :
174 (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
175 "RTREE" :
176 "BTREE");
181 @brief Callback function for open of a MERGE parent table.
183 @detail This function adds a TABLE_LIST object for a MERGE child table
184 to a list of tables of the parent TABLE object. It is called for
185 each child table.
187 The list of child TABLE_LIST objects is kept in the TABLE object of
188 the parent for the whole life time of the MERGE table. It is
189 inserted in the statement list behind the MERGE parent TABLE_LIST
190 object when the MERGE table is opened. It is removed from the
191 statement list after the last child is opened.
193 All memeory used for the child TABLE_LIST objects and the strings
194 referred by it are taken from the parent TABLE::mem_root. Thus they
195 are all freed implicitly at the final close of the table.
197 TABLE::child_l -> TABLE_LIST::next_global -> TABLE_LIST::next_global
198 # # ^ # ^
199 # # | # |
200 # # +--------- TABLE_LIST::prev_global
201 # # |
202 # |<--- TABLE_LIST::prev_global |
204 TABLE::child_last_l -----------------------------------------+
206 @param[in] callback_param data pointer as given to myrg_parent_open()
207 @param[in] filename file name of MyISAM table
208 without extension.
210 @return status
211 @retval 0 OK
212 @retval != 0 Error
215 static int myisammrg_parent_open_callback(void *callback_param,
216 const char *filename)
218 ha_myisammrg *ha_myrg= (ha_myisammrg*) callback_param;
219 TABLE *parent= ha_myrg->table_ptr();
220 TABLE_LIST *child_l;
221 size_t dirlen;
222 char dir_path[FN_REFLEN];
223 char name_buf[NAME_LEN];
224 DBUG_ENTER("myisammrg_parent_open_callback");
226 /* Get a TABLE_LIST object. */
227 if (!(child_l= (TABLE_LIST*) alloc_root(&parent->mem_root,
228 sizeof(TABLE_LIST))))
230 /* purecov: begin inspected */
231 DBUG_PRINT("error", ("my_malloc error: %d", my_errno));
232 DBUG_RETURN(1);
233 /* purecov: end */
235 bzero((char*) child_l, sizeof(TABLE_LIST));
238 Depending on MySQL version, filename may be encoded by table name to
239 file name encoding or not. Always encoded if parent table is created
240 by 5.1.46+. Encoded if parent is created by 5.1.6+ and child table is
241 in different database.
243 if (!has_path(filename))
245 /* Child is in the same database as parent. */
246 child_l->db_length= parent->s->db.length;
247 child_l->db= strmake_root(&parent->mem_root, parent->s->db.str,
248 child_l->db_length);
249 /* Child table name is encoded in parent dot-MRG starting with 5.1.46. */
250 if (parent->s->mysql_version >= 50146)
252 child_l->table_name_length= filename_to_tablename(filename, name_buf,
253 sizeof(name_buf));
254 child_l->table_name= strmake_root(&parent->mem_root, name_buf,
255 child_l->table_name_length);
257 else
259 child_l->table_name_length= strlen(filename);
260 child_l->table_name= strmake_root(&parent->mem_root, filename,
261 child_l->table_name_length);
264 else
266 DBUG_ASSERT(strlen(filename) < sizeof(dir_path));
267 fn_format(dir_path, filename, "", "", 0);
268 /* Extract child table name and database name from filename. */
269 dirlen= dirname_length(dir_path);
270 /* Child db/table name is encoded in parent dot-MRG starting with 5.1.6. */
271 if (parent->s->mysql_version >= 50106)
273 child_l->table_name_length= filename_to_tablename(dir_path + dirlen,
274 name_buf,
275 sizeof(name_buf));
276 child_l->table_name= strmake_root(&parent->mem_root, name_buf,
277 child_l->table_name_length);
278 dir_path[dirlen - 1]= 0;
279 dirlen= dirname_length(dir_path);
280 child_l->db_length= filename_to_tablename(dir_path + dirlen, name_buf,
281 sizeof(name_buf));
282 child_l->db= strmake_root(&parent->mem_root, name_buf, child_l->db_length);
284 else
286 child_l->table_name_length= strlen(dir_path + dirlen);
287 child_l->table_name= strmake_root(&parent->mem_root, dir_path + dirlen,
288 child_l->table_name_length);
289 dir_path[dirlen - 1]= 0;
290 dirlen= dirname_length(dir_path);
291 child_l->db_length= strlen(dir_path + dirlen);
292 child_l->db= strmake_root(&parent->mem_root, dir_path + dirlen,
293 child_l->db_length);
297 DBUG_PRINT("myrg", ("open: '%.*s'.'%.*s'", (int) child_l->db_length,
298 child_l->db, (int) child_l->table_name_length,
299 child_l->table_name));
301 /* Convert to lowercase if required. */
302 if (lower_case_table_names && child_l->table_name_length)
303 child_l->table_name_length= my_casedn_str(files_charset_info,
304 child_l->table_name);
305 /* Set alias. */
306 child_l->alias= child_l->table_name;
308 /* Initialize table map to 'undefined'. */
309 child_l->init_child_def_version();
311 /* Link TABLE_LIST object into the parent list. */
312 if (!parent->child_last_l)
314 /* Initialize parent->child_last_l when handling first child. */
315 parent->child_last_l= &parent->child_l;
317 *parent->child_last_l= child_l;
318 child_l->prev_global= parent->child_last_l;
319 parent->child_last_l= &child_l->next_global;
321 DBUG_RETURN(0);
326 @brief Callback function for attaching a MERGE child table.
328 @detail This function retrieves the MyISAM table handle from the
329 next child table. It is called for each child table.
331 @param[in] callback_param data pointer as given to
332 myrg_attach_children()
334 @return pointer to open MyISAM table structure
335 @retval !=NULL OK, returning pointer
336 @retval NULL, my_errno == 0 Ok, no more child tables
337 @retval NULL, my_errno != 0 error
340 static MI_INFO *myisammrg_attach_children_callback(void *callback_param)
342 ha_myisammrg *ha_myrg;
343 TABLE *parent;
344 TABLE *child;
345 TABLE_LIST *child_l;
346 MI_INFO *UNINIT_VAR(myisam);
347 DBUG_ENTER("myisammrg_attach_children_callback");
349 my_errno= 0;
350 ha_myrg= (ha_myisammrg*) callback_param;
351 parent= ha_myrg->table_ptr();
353 /* Get child list item. */
354 child_l= ha_myrg->next_child_attach;
355 if (!child_l)
357 DBUG_PRINT("myrg", ("No more children to attach"));
358 DBUG_RETURN(NULL);
360 child= child_l->table;
361 DBUG_PRINT("myrg", ("child table: '%s'.'%s' 0x%lx", child->s->db.str,
362 child->s->table_name.str, (long) child));
364 Prepare for next child. Used as child_l in next call to this function.
365 We cannot rely on a NULL-terminated chain.
367 if (&child_l->next_global == parent->child_last_l)
369 DBUG_PRINT("myrg", ("attaching last child"));
370 ha_myrg->next_child_attach= NULL;
372 else
373 ha_myrg->next_child_attach= child_l->next_global;
375 /* Set parent reference. */
376 child->parent= parent;
379 Do a quick compatibility check. The table def version is set when
380 the table share is created. The child def version is copied
381 from the table def version after a sucessful compatibility check.
382 We need to repeat the compatibility check only if a child is opened
383 from a different share than last time it was used with this MERGE
384 table.
386 DBUG_PRINT("myrg", ("table_def_version last: %lu current: %lu",
387 (ulong) child_l->get_child_def_version(),
388 (ulong) child->s->get_table_def_version()));
389 if (child_l->get_child_def_version() != child->s->get_table_def_version())
390 ha_myrg->need_compat_check= TRUE;
393 If parent is temporary, children must be temporary too and vice
394 versa. This check must be done for every child on every open because
395 the table def version can overlap between temporary and
396 non-temporary tables. We need to detect the case where a
397 non-temporary table has been replaced with a temporary table of the
398 same version. Or vice versa. A very unlikely case, but it could
399 happen.
401 if (child->s->tmp_table != parent->s->tmp_table)
403 DBUG_PRINT("error", ("temporary table mismatch parent: %d child: %d",
404 parent->s->tmp_table, child->s->tmp_table));
405 my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
406 goto err;
409 /* Extract the MyISAM table structure pointer from the handler object. */
410 if ((child->file->ht->db_type != DB_TYPE_MYISAM) ||
411 !(myisam= ((ha_myisam*) child->file)->file_ptr()))
413 DBUG_PRINT("error", ("no MyISAM handle for child table: '%s'.'%s' 0x%lx",
414 child->s->db.str, child->s->table_name.str,
415 (long) child));
416 my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
418 DBUG_PRINT("myrg", ("MyISAM handle: 0x%lx my_errno: %d",
419 my_errno ? 0L : (long) myisam, my_errno));
421 err:
422 DBUG_RETURN(my_errno ? NULL : myisam);
427 @brief Open a MERGE parent table, not its children.
429 @detail This function initializes the MERGE storage engine structures
430 and adds a child list of TABLE_LIST to the parent TABLE.
432 @param[in] name MERGE table path name
433 @param[in] mode read/write mode, unused
434 @param[in] test_if_locked_arg open flags
436 @return status
437 @retval 0 OK
438 @retval -1 Error, my_errno gives reason
441 int ha_myisammrg::open(const char *name, int mode __attribute__((unused)),
442 uint test_if_locked_arg)
444 DBUG_ENTER("ha_myisammrg::open");
445 DBUG_PRINT("myrg", ("name: '%s' table: 0x%lx", name, (long) table));
446 DBUG_PRINT("myrg", ("test_if_locked_arg: %u", test_if_locked_arg));
448 /* Save for later use. */
449 test_if_locked= test_if_locked_arg;
451 /* retrieve children table list. */
452 my_errno= 0;
453 if (is_cloned)
456 Open and attaches the MyISAM tables,that are under the MERGE table
457 parent, on the MyISAM storage engine interface directly within the
458 MERGE engine. The new MyISAM table instances, as well as the MERGE
459 clone itself, are not visible in the table cache. This is not a
460 problem because all locking is handled by the original MERGE table
461 from which this is cloned of.
463 if (!(file= myrg_open(name, table->db_stat, HA_OPEN_IGNORE_IF_LOCKED)))
465 DBUG_PRINT("error", ("my_errno %d", my_errno));
466 DBUG_RETURN(my_errno ? my_errno : -1);
469 file->children_attached= TRUE;
471 info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
473 else if (!(file= myrg_parent_open(name, myisammrg_parent_open_callback, this)))
475 DBUG_PRINT("error", ("my_errno %d", my_errno));
476 DBUG_RETURN(my_errno ? my_errno : -1);
478 DBUG_PRINT("myrg", ("MYRG_INFO: 0x%lx", (long) file));
479 DBUG_RETURN(0);
483 Returns a cloned instance of the current handler.
485 @return A cloned handler instance.
487 handler *ha_myisammrg::clone(const char *name, MEM_ROOT *mem_root)
489 MYRG_TABLE *u_table,*newu_table;
490 ha_myisammrg *new_handler=
491 (ha_myisammrg*) get_new_handler(table->s, mem_root, table->s->db_type());
492 if (!new_handler)
493 return NULL;
495 /* Inform ha_myisammrg::open() that it is a cloned handler */
496 new_handler->is_cloned= TRUE;
498 Allocate handler->ref here because otherwise ha_open will allocate it
499 on this->table->mem_root and we will not be able to reclaim that memory
500 when the clone handler object is destroyed.
502 if (!(new_handler->ref= (uchar*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2)))
504 delete new_handler;
505 return NULL;
508 if (new_handler->ha_open(table, name, table->db_stat,
509 HA_OPEN_IGNORE_IF_LOCKED))
511 delete new_handler;
512 return NULL;
516 Iterate through the original child tables and
517 copy the state into the cloned child tables.
518 We need to do this because all the child tables
519 can be involved in delete.
521 newu_table= new_handler->file->open_tables;
522 for (u_table= file->open_tables; u_table < file->end_table; u_table++)
524 newu_table->table->state= u_table->table->state;
525 newu_table++;
528 return new_handler;
533 @brief Attach children to a MERGE table.
535 @detail Let the storage engine attach its children through a callback
536 function. Check table definitions for consistency.
538 @note Special thd->open_options may be in effect. We can make use of
539 them in attach. I.e. we use HA_OPEN_FOR_REPAIR to report the names
540 of mismatching child tables. We cannot transport these options in
541 ha_myisammrg::test_if_locked because they may change after the
542 parent is opened. The parent is kept open in the table cache over
543 multiple statements and can be used by other threads. Open options
544 can change over time.
546 @return status
547 @retval 0 OK
548 @retval != 0 Error, my_errno gives reason
551 int ha_myisammrg::attach_children(void)
553 MYRG_TABLE *u_table;
554 MI_COLUMNDEF *recinfo;
555 MI_KEYDEF *keyinfo;
556 uint recs;
557 uint keys= table->s->keys;
558 int error;
559 DBUG_ENTER("ha_myisammrg::attach_children");
560 DBUG_PRINT("myrg", ("table: '%s'.'%s' 0x%lx", table->s->db.str,
561 table->s->table_name.str, (long) table));
562 DBUG_PRINT("myrg", ("test_if_locked: %u", this->test_if_locked));
563 DBUG_ASSERT(!this->file->children_attached);
566 Initialize variables that are used, modified, and/or set by
567 myisammrg_attach_children_callback().
568 'next_child_attach' traverses the chain of TABLE_LIST objects
569 that has been compiled during myrg_parent_open(). Every call
570 to myisammrg_attach_children_callback() moves the pointer to
571 the next object.
572 'need_compat_check' is set by myisammrg_attach_children_callback()
573 if a child fails the table def version check.
574 'my_errno' is set by myisammrg_attach_children_callback() in
575 case of an error.
577 next_child_attach= table->child_l;
578 need_compat_check= FALSE;
579 my_errno= 0;
581 if (myrg_attach_children(this->file, this->test_if_locked |
582 current_thd->open_options,
583 myisammrg_attach_children_callback, this,
584 (my_bool *) &need_compat_check))
586 DBUG_PRINT("error", ("my_errno %d", my_errno));
587 DBUG_RETURN(my_errno ? my_errno : -1);
589 DBUG_PRINT("myrg", ("calling myrg_extrafunc"));
590 myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref);
591 if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
592 test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
593 myrg_extra(file,HA_EXTRA_NO_WAIT_LOCK,0);
594 info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
595 if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
596 myrg_extra(file,HA_EXTRA_WAIT_LOCK,0);
599 The compatibility check is required only if one or more children do
600 not match their table def version from the last check. This will
601 always happen at the first attach because the reference child def
602 version is initialized to 'undefined' at open.
604 DBUG_PRINT("myrg", ("need_compat_check: %d", need_compat_check));
605 if (need_compat_check)
607 TABLE_LIST *child_l;
609 if (table->s->reclength != stats.mean_rec_length && stats.mean_rec_length)
611 DBUG_PRINT("error",("reclength: %lu mean_rec_length: %lu",
612 table->s->reclength, stats.mean_rec_length));
613 if (test_if_locked & HA_OPEN_FOR_REPAIR)
614 myrg_print_wrong_table(file->open_tables->table->filename);
615 error= HA_ERR_WRONG_MRG_TABLE_DEF;
616 goto err;
619 Both recinfo and keyinfo are allocated by my_multi_malloc(), thus
620 only recinfo must be freed.
622 if ((error= table2myisam(table, &keyinfo, &recinfo, &recs)))
624 /* purecov: begin inspected */
625 DBUG_PRINT("error", ("failed to convert TABLE object to MyISAM "
626 "key and column definition"));
627 goto err;
628 /* purecov: end */
630 for (u_table= file->open_tables; u_table < file->end_table; u_table++)
632 if (check_definition(keyinfo, recinfo, keys, recs,
633 u_table->table->s->keyinfo, u_table->table->s->rec,
634 u_table->table->s->base.keys,
635 u_table->table->s->base.fields, false, NULL))
637 DBUG_PRINT("error", ("table definition mismatch: '%s'",
638 u_table->table->filename));
639 error= HA_ERR_WRONG_MRG_TABLE_DEF;
640 if (!(this->test_if_locked & HA_OPEN_FOR_REPAIR))
642 my_free((uchar*) recinfo, MYF(0));
643 goto err;
645 myrg_print_wrong_table(u_table->table->filename);
648 my_free((uchar*) recinfo, MYF(0));
649 if (error == HA_ERR_WRONG_MRG_TABLE_DEF)
650 goto err;
652 /* All checks passed so far. Now update child def version. */
653 for (child_l= table->child_l; ; child_l= child_l->next_global)
655 child_l->set_child_def_version(
656 child_l->table->s->get_table_def_version());
658 if (&child_l->next_global == table->child_last_l)
659 break;
662 #if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4
663 /* Merge table has more than 2G rows */
664 if (table->s->crashed)
666 DBUG_PRINT("error", ("MERGE table marked crashed"));
667 error= HA_ERR_WRONG_MRG_TABLE_DEF;
668 goto err;
670 #endif
671 DBUG_RETURN(0);
673 err:
674 myrg_detach_children(file);
675 DBUG_RETURN(my_errno= error);
680 @brief Detach all children from a MERGE table.
682 @note Detach must not touch the children in any way.
683 They may have been closed at ths point already.
684 All references to the children should be removed.
686 @return status
687 @retval 0 OK
688 @retval != 0 Error, my_errno gives reason
691 int ha_myisammrg::detach_children(void)
693 DBUG_ENTER("ha_myisammrg::detach_children");
694 DBUG_ASSERT(this->file && this->file->children_attached);
696 if (myrg_detach_children(this->file))
698 /* purecov: begin inspected */
699 DBUG_PRINT("error", ("my_errno %d", my_errno));
700 DBUG_RETURN(my_errno ? my_errno : -1);
701 /* purecov: end */
703 DBUG_RETURN(0);
708 @brief Close a MERGE parent table, not its children.
710 @note The children are expected to be closed separately by the caller.
712 @return status
713 @retval 0 OK
714 @retval != 0 Error, my_errno gives reason
717 int ha_myisammrg::close(void)
719 int rc;
720 DBUG_ENTER("ha_myisammrg::close");
722 Children must not be attached here. Unless the MERGE table has no
723 children or the handler instance has been cloned. In these cases
724 children_attached is always true.
726 DBUG_ASSERT(!this->file->children_attached || !this->file->tables || this->is_cloned);
727 rc= myrg_close(file);
728 file= 0;
729 DBUG_RETURN(rc);
732 int ha_myisammrg::write_row(uchar * buf)
734 DBUG_ENTER("ha_myisammrg::write_row");
735 DBUG_ASSERT(this->file->children_attached);
736 ha_statistic_increment(&SSV::ha_write_count);
738 if (file->merge_insert_method == MERGE_INSERT_DISABLED || !file->tables)
739 DBUG_RETURN(HA_ERR_TABLE_READONLY);
741 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
742 table->timestamp_field->set_time();
743 if (table->next_number_field && buf == table->record[0])
745 int error;
746 if ((error= update_auto_increment()))
747 DBUG_RETURN(error); /* purecov: inspected */
749 DBUG_RETURN(myrg_write(file,buf));
752 int ha_myisammrg::update_row(const uchar * old_data, uchar * new_data)
754 DBUG_ASSERT(this->file->children_attached);
755 ha_statistic_increment(&SSV::ha_update_count);
756 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
757 table->timestamp_field->set_time();
758 return myrg_update(file,old_data,new_data);
761 int ha_myisammrg::delete_row(const uchar * buf)
763 DBUG_ASSERT(this->file->children_attached);
764 ha_statistic_increment(&SSV::ha_delete_count);
765 return myrg_delete(file,buf);
768 int ha_myisammrg::index_read_map(uchar * buf, const uchar * key,
769 key_part_map keypart_map,
770 enum ha_rkey_function find_flag)
772 DBUG_ASSERT(this->file->children_attached);
773 ha_statistic_increment(&SSV::ha_read_key_count);
774 int error=myrg_rkey(file,buf,active_index, key, keypart_map, find_flag);
775 table->status=error ? STATUS_NOT_FOUND: 0;
776 return error;
779 int ha_myisammrg::index_read_idx_map(uchar * buf, uint index, const uchar * key,
780 key_part_map keypart_map,
781 enum ha_rkey_function find_flag)
783 DBUG_ASSERT(this->file->children_attached);
784 ha_statistic_increment(&SSV::ha_read_key_count);
785 int error=myrg_rkey(file,buf,index, key, keypart_map, find_flag);
786 table->status=error ? STATUS_NOT_FOUND: 0;
787 return error;
790 int ha_myisammrg::index_read_last_map(uchar *buf, const uchar *key,
791 key_part_map keypart_map)
793 DBUG_ASSERT(this->file->children_attached);
794 ha_statistic_increment(&SSV::ha_read_key_count);
795 int error=myrg_rkey(file,buf,active_index, key, keypart_map,
796 HA_READ_PREFIX_LAST);
797 table->status=error ? STATUS_NOT_FOUND: 0;
798 return error;
801 int ha_myisammrg::index_next(uchar * buf)
803 DBUG_ASSERT(this->file->children_attached);
804 ha_statistic_increment(&SSV::ha_read_next_count);
805 int error=myrg_rnext(file,buf,active_index);
806 table->status=error ? STATUS_NOT_FOUND: 0;
807 return error;
810 int ha_myisammrg::index_prev(uchar * buf)
812 DBUG_ASSERT(this->file->children_attached);
813 ha_statistic_increment(&SSV::ha_read_prev_count);
814 int error=myrg_rprev(file,buf, active_index);
815 table->status=error ? STATUS_NOT_FOUND: 0;
816 return error;
819 int ha_myisammrg::index_first(uchar * buf)
821 DBUG_ASSERT(this->file->children_attached);
822 ha_statistic_increment(&SSV::ha_read_first_count);
823 int error=myrg_rfirst(file, buf, active_index);
824 table->status=error ? STATUS_NOT_FOUND: 0;
825 return error;
828 int ha_myisammrg::index_last(uchar * buf)
830 DBUG_ASSERT(this->file->children_attached);
831 ha_statistic_increment(&SSV::ha_read_last_count);
832 int error=myrg_rlast(file, buf, active_index);
833 table->status=error ? STATUS_NOT_FOUND: 0;
834 return error;
837 int ha_myisammrg::index_next_same(uchar * buf,
838 const uchar *key __attribute__((unused)),
839 uint length __attribute__((unused)))
841 int error;
842 DBUG_ASSERT(this->file->children_attached);
843 ha_statistic_increment(&SSV::ha_read_next_count);
846 error= myrg_rnext_same(file,buf);
847 } while (error == HA_ERR_RECORD_DELETED);
848 table->status=error ? STATUS_NOT_FOUND: 0;
849 return error;
853 int ha_myisammrg::rnd_init(bool scan)
855 DBUG_ASSERT(this->file->children_attached);
856 return myrg_reset(file);
860 int ha_myisammrg::rnd_next(uchar *buf)
862 DBUG_ASSERT(this->file->children_attached);
863 ha_statistic_increment(&SSV::ha_read_rnd_next_count);
864 int error=myrg_rrnd(file, buf, HA_OFFSET_ERROR);
865 table->status=error ? STATUS_NOT_FOUND: 0;
866 return error;
870 int ha_myisammrg::rnd_pos(uchar * buf, uchar *pos)
872 DBUG_ASSERT(this->file->children_attached);
873 ha_statistic_increment(&SSV::ha_read_rnd_count);
874 int error=myrg_rrnd(file, buf, my_get_ptr(pos,ref_length));
875 table->status=error ? STATUS_NOT_FOUND: 0;
876 return error;
879 void ha_myisammrg::position(const uchar *record)
881 DBUG_ASSERT(this->file->children_attached);
882 ulonglong row_position= myrg_position(file);
883 my_store_ptr(ref, ref_length, (my_off_t) row_position);
887 ha_rows ha_myisammrg::records_in_range(uint inx, key_range *min_key,
888 key_range *max_key)
890 DBUG_ASSERT(this->file->children_attached);
891 return (ha_rows) myrg_records_in_range(file, (int) inx, min_key, max_key);
895 int ha_myisammrg::info(uint flag)
897 MYMERGE_INFO mrg_info;
898 DBUG_ASSERT(this->file->children_attached);
899 (void) myrg_status(file,&mrg_info,flag);
901 The following fails if one has not compiled MySQL with -DBIG_TABLES
902 and one has more than 2^32 rows in the merge tables.
904 stats.records = (ha_rows) mrg_info.records;
905 stats.deleted = (ha_rows) mrg_info.deleted;
906 #if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4
907 if ((mrg_info.records >= (ulonglong) 1 << 32) ||
908 (mrg_info.deleted >= (ulonglong) 1 << 32))
909 table->s->crashed= 1;
910 #endif
911 stats.data_file_length= mrg_info.data_file_length;
912 if (mrg_info.errkey >= (int) table_share->keys)
915 If value of errkey is higher than the number of keys
916 on the table set errkey to MAX_KEY. This will be
917 treated as unknown key case and error message generator
918 won't try to locate key causing segmentation fault.
920 mrg_info.errkey= MAX_KEY;
922 table->s->keys_in_use.set_prefix(table->s->keys);
923 stats.mean_rec_length= mrg_info.reclength;
926 The handler::block_size is used all over the code in index scan cost
927 calculations. It is used to get number of disk seeks required to
928 retrieve a number of index tuples.
929 If the merge table has N underlying tables, then (assuming underlying
930 tables have equal size, the only "simple" approach we can use)
931 retrieving X index records from a merge table will require N times more
932 disk seeks compared to doing the same on a MyISAM table with equal
933 number of records.
934 In the edge case (file_tables > myisam_block_size) we'll get
935 block_size==0, and index calculation code will act as if we need one
936 disk seek to retrieve one index tuple.
938 TODO: In 5.2 index scan cost calculation will be factored out into a
939 virtual function in class handler and we'll be able to remove this hack.
941 stats.block_size= 0;
942 if (file->tables)
943 stats.block_size= myisam_block_size / file->tables;
945 stats.update_time= 0;
946 #if SIZEOF_OFF_T > 4
947 ref_length=6; // Should be big enough
948 #else
949 ref_length=4; // Can't be > than my_off_t
950 #endif
951 if (flag & HA_STATUS_CONST)
953 if (table->s->key_parts && mrg_info.rec_per_key)
955 #ifdef HAVE_purify
957 valgrind may be unhappy about it, because optimizer may access values
958 between file->keys and table->key_parts, that will be uninitialized.
959 It's safe though, because even if opimizer will decide to use a key
960 with such a number, it'll be an error later anyway.
962 bzero((char*) table->key_info[0].rec_per_key,
963 sizeof(table->key_info[0].rec_per_key[0]) * table->s->key_parts);
964 #endif
965 memcpy((char*) table->key_info[0].rec_per_key,
966 (char*) mrg_info.rec_per_key,
967 sizeof(table->key_info[0].rec_per_key[0]) *
968 min(file->keys, table->s->key_parts));
971 if (flag & HA_STATUS_ERRKEY)
973 errkey= mrg_info.errkey;
974 my_store_ptr(dup_ref, ref_length, mrg_info.dupp_key_pos);
976 return 0;
980 int ha_myisammrg::extra(enum ha_extra_function operation)
982 if (operation == HA_EXTRA_ATTACH_CHILDREN)
984 int rc= attach_children();
985 if (!rc)
986 (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
987 return(rc);
989 else if (operation == HA_EXTRA_DETACH_CHILDREN)
992 Note that detach must not touch the children in any way.
993 They may have been closed at ths point already.
995 int rc= detach_children();
996 return(rc);
999 /* As this is just a mapping, we don't have to force the underlying
1000 tables to be closed */
1001 if (operation == HA_EXTRA_FORCE_REOPEN ||
1002 operation == HA_EXTRA_PREPARE_FOR_DROP)
1003 return 0;
1004 return myrg_extra(file,operation,0);
1007 int ha_myisammrg::reset(void)
1009 return myrg_reset(file);
1012 /* To be used with WRITE_CACHE, EXTRA_CACHE and BULK_INSERT_BEGIN */
1014 int ha_myisammrg::extra_opt(enum ha_extra_function operation, ulong cache_size)
1016 DBUG_ASSERT(this->file->children_attached);
1017 if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE)
1018 return 0;
1019 return myrg_extra(file, operation, (void*) &cache_size);
1022 int ha_myisammrg::external_lock(THD *thd, int lock_type)
1024 DBUG_ASSERT(this->file->children_attached);
1025 return myrg_lock_database(file,lock_type);
1028 uint ha_myisammrg::lock_count(void) const
1031 Return the real lock count even if the children are not attached.
1032 This method is used for allocating memory. If we would return 0
1033 to another thread (e.g. doing FLUSH TABLE), and attach the children
1034 before the other thread calls store_lock(), then we would return
1035 more locks in store_lock() than we claimed by lock_count(). The
1036 other tread would overrun its memory.
1038 return file->tables;
1042 THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd,
1043 THR_LOCK_DATA **to,
1044 enum thr_lock_type lock_type)
1046 MYRG_TABLE *open_table;
1049 This method can be called while another thread is attaching the
1050 children. If the processor reorders instructions or write to memory,
1051 'children_attached' could be set before 'open_tables' has all the
1052 pointers to the children. Use of a mutex here and in
1053 myrg_attach_children() forces consistent data.
1055 pthread_mutex_lock(&this->file->mutex);
1058 When MERGE table is open, but not yet attached, other threads
1059 could flush it, which means call mysql_lock_abort_for_thread()
1060 on this threads TABLE. 'children_attached' is FALSE in this
1061 situaton. Since the table is not locked, return no lock data.
1063 if (!this->file->children_attached)
1064 goto end; /* purecov: tested */
1066 for (open_table=file->open_tables ;
1067 open_table != file->end_table ;
1068 open_table++)
1070 *(to++)= &open_table->table->lock;
1071 if (lock_type != TL_IGNORE && open_table->table->lock.type == TL_UNLOCK)
1072 open_table->table->lock.type=lock_type;
1075 end:
1076 pthread_mutex_unlock(&this->file->mutex);
1077 return to;
1081 /* Find out database name and table name from a filename */
1083 static void split_file_name(const char *file_name,
1084 LEX_STRING *db, LEX_STRING *name)
1086 size_t dir_length, prefix_length;
1087 char buff[FN_REFLEN];
1089 db->length= 0;
1090 strmake(buff, file_name, sizeof(buff)-1);
1091 dir_length= dirname_length(buff);
1092 if (dir_length > 1)
1094 /* Get database */
1095 buff[dir_length-1]= 0; // Remove end '/'
1096 prefix_length= dirname_length(buff);
1097 db->str= (char*) file_name+ prefix_length;
1098 db->length= dir_length - prefix_length -1;
1100 name->str= (char*) file_name+ dir_length;
1101 name->length= (uint) (fn_ext(name->str) - name->str);
1105 void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info)
1107 DBUG_ENTER("ha_myisammrg::update_create_info");
1109 if (!(create_info->used_fields & HA_CREATE_USED_UNION))
1111 MYRG_TABLE *open_table;
1112 THD *thd=current_thd;
1114 create_info->merge_list.next= &create_info->merge_list.first;
1115 create_info->merge_list.elements=0;
1117 for (open_table=file->open_tables ;
1118 open_table != file->end_table ;
1119 open_table++)
1121 TABLE_LIST *ptr;
1122 LEX_STRING db, name;
1123 LINT_INIT(db.str);
1125 if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
1126 goto err;
1127 split_file_name(open_table->table->filename, &db, &name);
1128 if (!(ptr->table_name= thd->strmake(name.str, name.length)))
1129 goto err;
1130 if (db.length && !(ptr->db= thd->strmake(db.str, db.length)))
1131 goto err;
1133 create_info->merge_list.elements++;
1134 (*create_info->merge_list.next) = ptr;
1135 create_info->merge_list.next= &ptr->next_local;
1137 *create_info->merge_list.next=0;
1139 if (!(create_info->used_fields & HA_CREATE_USED_INSERT_METHOD))
1141 create_info->merge_insert_method = file->merge_insert_method;
1143 DBUG_VOID_RETURN;
1145 err:
1146 create_info->merge_list.elements=0;
1147 create_info->merge_list.first=0;
1148 DBUG_VOID_RETURN;
1152 int ha_myisammrg::create(const char *name, register TABLE *form,
1153 HA_CREATE_INFO *create_info)
1155 char buff[FN_REFLEN];
1156 const char **table_names, **pos;
1157 TABLE_LIST *tables= create_info->merge_list.first;
1158 THD *thd= current_thd;
1159 size_t dirlgt= dirname_length(name);
1160 DBUG_ENTER("ha_myisammrg::create");
1162 /* Allocate a table_names array in thread mem_root. */
1163 if (!(table_names= (const char**)
1164 thd->alloc((create_info->merge_list.elements+1) * sizeof(char*))))
1165 DBUG_RETURN(HA_ERR_OUT_OF_MEM);
1167 /* Create child path names. */
1168 for (pos= table_names; tables; tables= tables->next_local)
1170 const char *table_name= buff;
1173 Construct the path to the MyISAM table. Try to meet two conditions:
1174 1.) Allow to include MyISAM tables from different databases, and
1175 2.) allow for moving DATADIR around in the file system.
1176 The first means that we need paths in the .MRG file. The second
1177 means that we should not have absolute paths in the .MRG file.
1178 The best, we can do, is to use 'mysql_data_home', which is '.'
1179 in mysqld and may be an absolute path in an embedded server.
1180 This means that it might not be possible to move the DATADIR of
1181 an embedded server without changing the paths in the .MRG file.
1183 Do the same even for temporary tables. MERGE children are now
1184 opened through the table cache. They are opened by db.table_name,
1185 not by their path name.
1187 uint length= build_table_filename(buff, sizeof(buff),
1188 tables->db, tables->table_name, "", 0);
1190 If a MyISAM table is in the same directory as the MERGE table,
1191 we use the table name without a path. This means that the
1192 DATADIR can easily be moved even for an embedded server as long
1193 as the MyISAM tables are from the same database as the MERGE table.
1195 if ((dirname_length(buff) == dirlgt) && ! memcmp(buff, name, dirlgt))
1197 table_name+= dirlgt;
1198 length-= dirlgt;
1200 if (!(table_name= thd->strmake(table_name, length)))
1201 DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
1203 *pos++= table_name;
1205 *pos=0;
1207 /* Create a MERGE meta file from the table_names array. */
1208 DBUG_RETURN(myrg_create(fn_format(buff,name,"","",
1209 MY_RESOLVE_SYMLINKS|
1210 MY_UNPACK_FILENAME|MY_APPEND_EXT),
1211 table_names,
1212 create_info->merge_insert_method,
1213 (my_bool) 0));
1217 void ha_myisammrg::append_create_info(String *packet)
1219 const char *current_db;
1220 size_t db_length;
1221 THD *thd= current_thd;
1222 TABLE_LIST *open_table, *first;
1224 if (file->merge_insert_method != MERGE_INSERT_DISABLED)
1226 packet->append(STRING_WITH_LEN(" INSERT_METHOD="));
1227 packet->append(get_type(&merge_insert_method,file->merge_insert_method-1));
1230 There is no sence adding UNION clause in case there is no underlying
1231 tables specified.
1233 if (file->open_tables == file->end_table)
1234 return;
1235 packet->append(STRING_WITH_LEN(" UNION=("));
1237 current_db= table->s->db.str;
1238 db_length= table->s->db.length;
1240 for (first= open_table= table->child_l;;
1241 open_table= open_table->next_global)
1243 LEX_STRING db= { open_table->db, open_table->db_length };
1245 if (open_table != first)
1246 packet->append(',');
1247 /* Report database for mapped table if it isn't in current database */
1248 if (db.length &&
1249 (db_length != db.length ||
1250 strncmp(current_db, db.str, db.length)))
1252 append_identifier(thd, packet, db.str, db.length);
1253 packet->append('.');
1255 append_identifier(thd, packet, open_table->table_name,
1256 open_table->table_name_length);
1257 if (&open_table->next_global == table->child_last_l)
1258 break;
1260 packet->append(')');
1264 bool ha_myisammrg::check_if_incompatible_data(HA_CREATE_INFO *info,
1265 uint table_changes)
1268 For myisammrg, we should always re-generate the mapping file as this
1269 is trivial to do
1271 return COMPATIBLE_DATA_NO;
1275 int ha_myisammrg::check(THD* thd, HA_CHECK_OPT* check_opt)
1277 return HA_ADMIN_OK;
1281 ha_rows ha_myisammrg::records()
1283 return myrg_records(file);
1287 extern int myrg_panic(enum ha_panic_function flag);
1288 int myisammrg_panic(handlerton *hton, ha_panic_function flag)
1290 return myrg_panic(flag);
1293 static int myisammrg_init(void *p)
1295 handlerton *myisammrg_hton;
1297 myisammrg_hton= (handlerton *)p;
1299 myisammrg_hton->db_type= DB_TYPE_MRG_MYISAM;
1300 myisammrg_hton->create= myisammrg_create_handler;
1301 myisammrg_hton->panic= myisammrg_panic;
1302 myisammrg_hton->flags= HTON_NO_PARTITION;
1304 return 0;
1307 struct st_mysql_storage_engine myisammrg_storage_engine=
1308 { MYSQL_HANDLERTON_INTERFACE_VERSION };
1310 mysql_declare_plugin(myisammrg)
1312 MYSQL_STORAGE_ENGINE_PLUGIN,
1313 &myisammrg_storage_engine,
1314 "MRG_MYISAM",
1315 "MySQL AB",
1316 "Collection of identical MyISAM tables",
1317 PLUGIN_LICENSE_GPL,
1318 myisammrg_init, /* Plugin Init */
1319 NULL, /* Plugin Deinit */
1320 0x0100, /* 1.0 */
1321 NULL, /* status variables */
1322 NULL, /* system variables */
1323 NULL /* config options */
1325 mysql_declare_plugin_end;