mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / myisam / ha_myisam.cc
blob173dc356778ff59da11641842b3a56bb6d2439eb
1 /*
2 Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifdef USE_PRAGMA_IMPLEMENTATION
20 #pragma implementation // gcc: Class implementation
21 #endif
23 #define MYSQL_SERVER 1
24 #include "mysql_priv.h"
25 #include <mysql/plugin.h>
26 #include <m_ctype.h>
27 #include <my_bit.h>
28 #include <myisampack.h>
29 #include "ha_myisam.h"
30 #include <stdarg.h>
31 #include "myisamdef.h"
32 #include "rt_index.h"
34 ulong myisam_recover_options= HA_RECOVER_NONE;
36 /* bits in myisam_recover_options */
37 const char *myisam_recover_names[] =
38 { "DEFAULT", "BACKUP", "FORCE", "QUICK", NullS};
39 TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
40 myisam_recover_names, NULL};
42 const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
43 "nulls_ignored", NullS};
44 TYPELIB myisam_stats_method_typelib= {
45 array_elements(myisam_stats_method_names) - 1, "",
46 myisam_stats_method_names, NULL};
48 #ifndef DBUG_OFF
49 /**
50 Causes the thread to wait in a spin lock for a query kill signal.
51 This function is used by the test frame work to identify race conditions.
53 The signal is caught and ignored and the thread is not killed.
56 static void debug_wait_for_kill(const char *info)
58 DBUG_ENTER("debug_wait_for_kill");
59 const char *prev_info;
60 THD *thd;
61 thd= current_thd;
62 prev_info= thd_proc_info(thd, info);
63 while(!thd->killed)
64 my_sleep(1000);
65 DBUG_PRINT("info", ("Exit debug_wait_for_kill"));
66 thd_proc_info(thd, prev_info);
67 DBUG_VOID_RETURN;
69 #endif
71 /*****************************************************************************
72 ** MyISAM tables
73 *****************************************************************************/
75 static handler *myisam_create_handler(handlerton *hton,
76 TABLE_SHARE *table,
77 MEM_ROOT *mem_root)
79 return new (mem_root) ha_myisam(hton, table);
82 // collect errors printed by mi_check routines
84 static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
85 const char *fmt, va_list args)
87 THD* thd = (THD*)param->thd;
88 Protocol *protocol= thd->protocol;
89 size_t length, msg_length;
90 char msgbuf[MI_MAX_MSG_BUF];
91 char name[NAME_LEN*2+2];
93 msg_length= my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
94 msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
96 DBUG_PRINT(msg_type,("message: %s",msgbuf));
98 if (!thd->vio_ok())
100 sql_print_error("%s", msgbuf);
101 return;
104 if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
105 T_AUTO_REPAIR))
107 my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
108 return;
110 length=(uint) (strxmov(name, param->db_name,".",param->table_name,NullS) -
111 name);
113 TODO: switch from protocol to push_warning here. The main reason we didn't
114 it yet is parallel repair. Due to following trace:
115 mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
117 Also we likely need to lock mutex here (in both cases with protocol and
118 push_warning).
120 #ifdef THREAD
121 if (param->need_print_msg_lock)
122 pthread_mutex_lock(&param->print_msg_mutex);
123 #endif
124 protocol->prepare_for_resend();
125 protocol->store(name, length, system_charset_info);
126 protocol->store(param->op_name, system_charset_info);
127 protocol->store(msg_type, system_charset_info);
128 protocol->store(msgbuf, msg_length, system_charset_info);
129 if (protocol->write())
130 sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
131 msgbuf);
132 #ifdef THREAD
133 if (param->need_print_msg_lock)
134 pthread_mutex_unlock(&param->print_msg_mutex);
135 #endif
136 return;
141 Convert TABLE object to MyISAM key and column definition
143 SYNOPSIS
144 table2myisam()
145 table_arg in TABLE object.
146 keydef_out out MyISAM key definition.
147 recinfo_out out MyISAM column definition.
148 records_out out Number of fields.
150 DESCRIPTION
151 This function will allocate and initialize MyISAM key and column
152 definition for further use in mi_create or for a check for underlying
153 table conformance in merge engine.
155 The caller needs to free *recinfo_out after use. Since *recinfo_out
156 and *keydef_out are allocated with a my_multi_malloc, *keydef_out
157 is freed automatically when *recinfo_out is freed.
159 RETURN VALUE
160 0 OK
161 !0 error code
164 int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
165 MI_COLUMNDEF **recinfo_out, uint *records_out)
167 uint i, j, recpos, minpos, fieldpos, temp_length, length;
168 enum ha_base_keytype type= HA_KEYTYPE_BINARY;
169 uchar *record;
170 KEY *pos;
171 MI_KEYDEF *keydef;
172 MI_COLUMNDEF *recinfo, *recinfo_pos;
173 HA_KEYSEG *keyseg;
174 TABLE_SHARE *share= table_arg->s;
175 uint options= share->db_options_in_use;
176 DBUG_ENTER("table2myisam");
177 if (!(my_multi_malloc(MYF(MY_WME),
178 recinfo_out, (share->fields * 2 + 2) * sizeof(MI_COLUMNDEF),
179 keydef_out, share->keys * sizeof(MI_KEYDEF),
180 &keyseg,
181 (share->key_parts + share->keys) * sizeof(HA_KEYSEG),
182 NullS)))
183 DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
184 keydef= *keydef_out;
185 recinfo= *recinfo_out;
186 pos= table_arg->key_info;
187 for (i= 0; i < share->keys; i++, pos++)
189 keydef[i].flag= ((uint16) pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL));
190 keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ?
191 (pos->flags & HA_SPATIAL ? HA_KEY_ALG_RTREE : HA_KEY_ALG_BTREE) :
192 pos->algorithm;
193 keydef[i].block_length= pos->block_size;
194 keydef[i].seg= keyseg;
195 keydef[i].keysegs= pos->key_parts;
196 for (j= 0; j < pos->key_parts; j++)
198 Field *field= pos->key_part[j].field;
199 type= field->key_type();
200 keydef[i].seg[j].flag= pos->key_part[j].key_part_flag;
202 if (options & HA_OPTION_PACK_KEYS ||
203 (pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY |
204 HA_SPACE_PACK_USED)))
206 if (pos->key_part[j].length > 8 &&
207 (type == HA_KEYTYPE_TEXT ||
208 type == HA_KEYTYPE_NUM ||
209 (type == HA_KEYTYPE_BINARY && !field->zero_pack())))
211 /* No blobs here */
212 if (j == 0)
213 keydef[i].flag|= HA_PACK_KEY;
214 if (!(field->flags & ZEROFILL_FLAG) &&
215 (field->type() == MYSQL_TYPE_STRING ||
216 field->type() == MYSQL_TYPE_VAR_STRING ||
217 ((int) (pos->key_part[j].length - field->decimals())) >= 4))
218 keydef[i].seg[j].flag|= HA_SPACE_PACK;
220 else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16))
221 keydef[i].flag|= HA_BINARY_PACK_KEY;
223 keydef[i].seg[j].type= (int) type;
224 keydef[i].seg[j].start= pos->key_part[j].offset;
225 keydef[i].seg[j].length= pos->key_part[j].length;
226 keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_end=
227 keydef[i].seg[j].bit_length= 0;
228 keydef[i].seg[j].bit_pos= 0;
229 keydef[i].seg[j].language= field->charset()->number;
231 if (field->null_ptr)
233 keydef[i].seg[j].null_bit= field->null_bit;
234 keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
235 (uchar*) table_arg->record[0]);
237 else
239 keydef[i].seg[j].null_bit= 0;
240 keydef[i].seg[j].null_pos= 0;
242 if (field->type() == MYSQL_TYPE_BLOB ||
243 field->type() == MYSQL_TYPE_GEOMETRY)
245 keydef[i].seg[j].flag|= HA_BLOB_PART;
246 /* save number of bytes used to pack length */
247 keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
248 share->blob_ptr_size);
250 else if (field->type() == MYSQL_TYPE_BIT)
252 keydef[i].seg[j].bit_length= ((Field_bit *) field)->bit_len;
253 keydef[i].seg[j].bit_start= ((Field_bit *) field)->bit_ofs;
254 keydef[i].seg[j].bit_pos= (uint) (((Field_bit *) field)->bit_ptr -
255 (uchar*) table_arg->record[0]);
258 keyseg+= pos->key_parts;
260 if (table_arg->found_next_number_field)
261 keydef[share->next_number_index].flag|= HA_AUTO_KEY;
262 record= table_arg->record[0];
263 recpos= 0;
264 recinfo_pos= recinfo;
265 while (recpos < (uint) share->reclength)
267 Field **field, *found= 0;
268 minpos= share->reclength;
269 length= 0;
271 for (field= table_arg->field; *field; field++)
273 if ((fieldpos= (*field)->offset(record)) >= recpos &&
274 fieldpos <= minpos)
276 /* skip null fields */
277 if (!(temp_length= (*field)->pack_length_in_rec()))
278 continue; /* Skip null-fields */
279 if (! found || fieldpos < minpos ||
280 (fieldpos == minpos && temp_length < length))
282 minpos= fieldpos;
283 found= *field;
284 length= temp_length;
288 DBUG_PRINT("loop", ("found: 0x%lx recpos: %d minpos: %d length: %d",
289 (long) found, recpos, minpos, length));
290 if (recpos != minpos)
291 { // Reserved space (Null bits?)
292 bzero((char*) recinfo_pos, sizeof(*recinfo_pos));
293 recinfo_pos->type= (int) FIELD_NORMAL;
294 recinfo_pos++->length= (uint16) (minpos - recpos);
296 if (!found)
297 break;
299 if (found->flags & BLOB_FLAG)
300 recinfo_pos->type= (int) FIELD_BLOB;
301 else if (found->type() == MYSQL_TYPE_VARCHAR)
302 recinfo_pos->type= FIELD_VARCHAR;
303 else if (!(options & HA_OPTION_PACK_RECORD))
304 recinfo_pos->type= (int) FIELD_NORMAL;
305 else if (found->zero_pack())
306 recinfo_pos->type= (int) FIELD_SKIP_ZERO;
307 else
308 recinfo_pos->type= (int) ((length <= 3 ||
309 (found->flags & ZEROFILL_FLAG)) ?
310 FIELD_NORMAL :
311 found->type() == MYSQL_TYPE_STRING ||
312 found->type() == MYSQL_TYPE_VAR_STRING ?
313 FIELD_SKIP_ENDSPACE :
314 FIELD_SKIP_PRESPACE);
315 if (found->null_ptr)
317 recinfo_pos->null_bit= found->null_bit;
318 recinfo_pos->null_pos= (uint) (found->null_ptr -
319 (uchar*) table_arg->record[0]);
321 else
323 recinfo_pos->null_bit= 0;
324 recinfo_pos->null_pos= 0;
326 (recinfo_pos++)->length= (uint16) length;
327 recpos= minpos + length;
328 DBUG_PRINT("loop", ("length: %d type: %d",
329 recinfo_pos[-1].length,recinfo_pos[-1].type));
331 *records_out= (uint) (recinfo_pos - recinfo);
332 DBUG_RETURN(0);
337 Check for underlying table conformance
339 SYNOPSIS
340 check_definition()
341 t1_keyinfo in First table key definition
342 t1_recinfo in First table record definition
343 t1_keys in Number of keys in first table
344 t1_recs in Number of records in first table
345 t2_keyinfo in Second table key definition
346 t2_recinfo in Second table record definition
347 t2_keys in Number of keys in second table
348 t2_recs in Number of records in second table
349 strict in Strict check switch
350 table in handle to the table object
352 DESCRIPTION
353 This function compares two MyISAM definitions. By intention it was done
354 to compare merge table definition against underlying table definition.
355 It may also be used to compare dot-frm and MYI definitions of MyISAM
356 table as well to compare different MyISAM table definitions.
358 For merge table it is not required that number of keys in merge table
359 must exactly match number of keys in underlying table. When calling this
360 function for underlying table conformance check, 'strict' flag must be
361 set to false, and converted merge definition must be passed as t1_*.
363 Otherwise 'strict' flag must be set to 1 and it is not required to pass
364 converted dot-frm definition as t1_*.
366 For compatibility reasons we relax some checks, specifically:
367 - 4.0 (and earlier versions) always set key_alg to 0.
368 - 4.0 (and earlier versions) have the same language for all keysegs.
370 RETURN VALUE
371 0 - Equal definitions.
372 1 - Different definitions.
374 TODO
375 - compare FULLTEXT keys;
376 - compare SPATIAL keys;
377 - compare FIELD_SKIP_ZERO which is converted to FIELD_NORMAL correctly
378 (should be corretly detected in table2myisam).
381 int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
382 uint t1_keys, uint t1_recs,
383 MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
384 uint t2_keys, uint t2_recs, bool strict, TABLE *table_arg)
386 uint i, j;
387 DBUG_ENTER("check_definition");
388 my_bool mysql_40_compat= table_arg && table_arg->s->frm_version < FRM_VER_TRUE_VARCHAR;
389 if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys))
391 DBUG_PRINT("error", ("Number of keys differs: t1_keys=%u, t2_keys=%u",
392 t1_keys, t2_keys));
393 DBUG_RETURN(1);
395 if (t1_recs != t2_recs)
397 DBUG_PRINT("error", ("Number of recs differs: t1_recs=%u, t2_recs=%u",
398 t1_recs, t2_recs));
399 DBUG_RETURN(1);
401 for (i= 0; i < t1_keys; i++)
403 HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg;
404 HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg;
405 if (t1_keyinfo[i].flag & HA_FULLTEXT && t2_keyinfo[i].flag & HA_FULLTEXT)
406 continue;
407 else if (t1_keyinfo[i].flag & HA_FULLTEXT ||
408 t2_keyinfo[i].flag & HA_FULLTEXT)
410 DBUG_PRINT("error", ("Key %d has different definition", i));
411 DBUG_PRINT("error", ("t1_fulltext= %d, t2_fulltext=%d",
412 test(t1_keyinfo[i].flag & HA_FULLTEXT),
413 test(t2_keyinfo[i].flag & HA_FULLTEXT)));
414 DBUG_RETURN(1);
416 if (t1_keyinfo[i].flag & HA_SPATIAL && t2_keyinfo[i].flag & HA_SPATIAL)
417 continue;
418 else if (t1_keyinfo[i].flag & HA_SPATIAL ||
419 t2_keyinfo[i].flag & HA_SPATIAL)
421 DBUG_PRINT("error", ("Key %d has different definition", i));
422 DBUG_PRINT("error", ("t1_spatial= %d, t2_spatial=%d",
423 test(t1_keyinfo[i].flag & HA_SPATIAL),
424 test(t2_keyinfo[i].flag & HA_SPATIAL)));
425 DBUG_RETURN(1);
427 if ((!mysql_40_compat &&
428 t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg) ||
429 t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs)
431 DBUG_PRINT("error", ("Key %d has different definition", i));
432 DBUG_PRINT("error", ("t1_keysegs=%d, t1_key_alg=%d",
433 t1_keyinfo[i].keysegs, t1_keyinfo[i].key_alg));
434 DBUG_PRINT("error", ("t2_keysegs=%d, t2_key_alg=%d",
435 t2_keyinfo[i].keysegs, t2_keyinfo[i].key_alg));
436 DBUG_RETURN(1);
438 for (j= t1_keyinfo[i].keysegs; j--;)
440 uint8 t1_keysegs_j__type= t1_keysegs[j].type;
443 Table migration from 4.1 to 5.1. In 5.1 a *TEXT key part is
444 always HA_KEYTYPE_VARTEXT2. In 4.1 we had only the equivalent of
445 HA_KEYTYPE_VARTEXT1. Since we treat both the same on MyISAM
446 level, we can ignore a mismatch between these types.
448 if ((t1_keysegs[j].flag & HA_BLOB_PART) &&
449 (t2_keysegs[j].flag & HA_BLOB_PART))
451 if ((t1_keysegs_j__type == HA_KEYTYPE_VARTEXT2) &&
452 (t2_keysegs[j].type == HA_KEYTYPE_VARTEXT1))
453 t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1; /* purecov: tested */
454 else if ((t1_keysegs_j__type == HA_KEYTYPE_VARBINARY2) &&
455 (t2_keysegs[j].type == HA_KEYTYPE_VARBINARY1))
456 t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1; /* purecov: inspected */
459 if ((!mysql_40_compat &&
460 t1_keysegs[j].language != t2_keysegs[j].language) ||
461 t1_keysegs_j__type != t2_keysegs[j].type ||
462 t1_keysegs[j].null_bit != t2_keysegs[j].null_bit ||
463 t1_keysegs[j].length != t2_keysegs[j].length)
465 DBUG_PRINT("error", ("Key segment %d (key %d) has different "
466 "definition", j, i));
467 DBUG_PRINT("error", ("t1_type=%d, t1_language=%d, t1_null_bit=%d, "
468 "t1_length=%d",
469 t1_keysegs[j].type, t1_keysegs[j].language,
470 t1_keysegs[j].null_bit, t1_keysegs[j].length));
471 DBUG_PRINT("error", ("t2_type=%d, t2_language=%d, t2_null_bit=%d, "
472 "t2_length=%d",
473 t2_keysegs[j].type, t2_keysegs[j].language,
474 t2_keysegs[j].null_bit, t2_keysegs[j].length));
476 DBUG_RETURN(1);
480 for (i= 0; i < t1_recs; i++)
482 MI_COLUMNDEF *t1_rec= &t1_recinfo[i];
483 MI_COLUMNDEF *t2_rec= &t2_recinfo[i];
485 FIELD_SKIP_ZERO can be changed to FIELD_NORMAL in mi_create,
486 see NOTE1 in mi_create.c
488 if ((t1_rec->type != t2_rec->type &&
489 !(t1_rec->type == (int) FIELD_SKIP_ZERO &&
490 t1_rec->length == 1 &&
491 t2_rec->type == (int) FIELD_NORMAL)) ||
492 t1_rec->length != t2_rec->length ||
493 t1_rec->null_bit != t2_rec->null_bit)
495 DBUG_PRINT("error", ("Field %d has different definition", i));
496 DBUG_PRINT("error", ("t1_type=%d, t1_length=%d, t1_null_bit=%d",
497 t1_rec->type, t1_rec->length, t1_rec->null_bit));
498 DBUG_PRINT("error", ("t2_type=%d, t2_length=%d, t2_null_bit=%d",
499 t2_rec->type, t2_rec->length, t2_rec->null_bit));
500 DBUG_RETURN(1);
503 DBUG_RETURN(0);
507 extern "C" {
509 volatile int *killed_ptr(MI_CHECK *param)
511 /* In theory Unsafe conversion, but should be ok for now */
512 return (int*) &(((THD *)(param->thd))->killed);
515 void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
517 param->error_printed|=1;
518 param->out_flag|= O_DATA_LOST;
519 va_list args;
520 va_start(args, fmt);
521 mi_check_print_msg(param, "error", fmt, args);
522 va_end(args);
525 void mi_check_print_info(MI_CHECK *param, const char *fmt,...)
527 va_list args;
528 va_start(args, fmt);
529 mi_check_print_msg(param, "info", fmt, args);
530 va_end(args);
533 void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
535 param->warning_printed=1;
536 param->out_flag|= O_DATA_LOST;
537 va_list args;
538 va_start(args, fmt);
539 mi_check_print_msg(param, "warning", fmt, args);
540 va_end(args);
546 ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
547 :handler(hton, table_arg), file(0),
548 int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
549 HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
550 HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
551 HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS |
552 HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS |
553 HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT),
554 can_enable_indexes(1)
557 handler *ha_myisam::clone(const char *name, MEM_ROOT *mem_root)
559 ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(name,
560 mem_root));
561 if (new_handler)
562 new_handler->file->state= file->state;
563 return new_handler;
567 static const char *ha_myisam_exts[] = {
568 ".MYI",
569 ".MYD",
570 NullS
573 const char **ha_myisam::bas_ext() const
575 return ha_myisam_exts;
579 const char *ha_myisam::index_type(uint key_number)
581 return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
582 "FULLTEXT" :
583 (table->key_info[key_number].flags & HA_SPATIAL) ?
584 "SPATIAL" :
585 (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
586 "RTREE" :
587 "BTREE");
590 #ifdef HAVE_REPLICATION
591 int ha_myisam::net_read_dump(NET* net)
593 int data_fd = file->dfile;
594 int error = 0;
596 if (my_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME)) == MY_FILEPOS_ERROR)
598 error= my_errno;
599 goto err;
601 for (;;)
603 ulong packet_len = my_net_read(net);
604 if (!packet_len)
605 break ; // end of file
606 if (packet_len == packet_error)
608 sql_print_error("ha_myisam::net_read_dump - read error ");
609 error= -1;
610 goto err;
612 if (my_write(data_fd, (uchar*)net->read_pos, (uint) packet_len,
613 MYF(MY_WME|MY_FNABP)))
615 error = errno;
616 goto err;
619 err:
620 return error;
624 int ha_myisam::dump(THD* thd, int fd)
626 MYISAM_SHARE* share = file->s;
627 NET* net = &thd->net;
628 uint blocksize = share->blocksize;
629 my_off_t bytes_to_read = share->state.state.data_file_length;
630 int data_fd = file->dfile;
631 uchar *buf = (uchar*) my_malloc(blocksize, MYF(MY_WME));
632 if (!buf)
633 return ENOMEM;
635 int error = 0;
636 if (my_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME)) == MY_FILEPOS_ERROR)
638 error= my_errno;
639 goto err;
641 for (; bytes_to_read > 0;)
643 size_t bytes = my_read(data_fd, buf, blocksize, MYF(MY_WME));
644 if (bytes == MY_FILE_ERROR)
646 error = errno;
647 goto err;
650 if (fd >= 0)
652 if (my_write(fd, buf, bytes, MYF(MY_WME | MY_FNABP)))
654 error = errno ? errno : EPIPE;
655 goto err;
658 else
660 if (my_net_write(net, buf, bytes))
662 error = errno ? errno : EPIPE;
663 goto err;
666 bytes_to_read -= bytes;
669 if (fd < 0)
671 if (my_net_write(net, (uchar*) "", 0))
672 error = errno ? errno : EPIPE;
673 net_flush(net);
676 err:
677 my_free((uchar*) buf, MYF(0));
678 return error;
680 #endif /* HAVE_REPLICATION */
683 /* Name is here without an extension */
684 int ha_myisam::open(const char *name, int mode, uint test_if_locked)
686 MI_KEYDEF *keyinfo;
687 MI_COLUMNDEF *recinfo= 0;
688 uint recs;
689 uint i;
692 If the user wants to have memory mapped data files, add an
693 open_flag. Do not memory map temporary tables because they are
694 expected to be inserted and thus extended a lot. Memory mapping is
695 efficient for files that keep their size, but very inefficient for
696 growing files. Using an open_flag instead of calling mi_extra(...
697 HA_EXTRA_MMAP ...) after mi_open() has the advantage that the
698 mapping is not repeated for every open, but just done on the initial
699 open, when the MyISAM share is created. Everytime the server
700 requires to open a new instance of a table it calls this method. We
701 will always supply HA_OPEN_MMAP for a permanent table. However, the
702 MyISAM storage engine will ignore this flag if this is a secondary
703 open of a table that is in use by other threads already (if the
704 MyISAM share exists already).
706 if (!(test_if_locked & HA_OPEN_TMP_TABLE) && opt_myisam_use_mmap)
707 test_if_locked|= HA_OPEN_MMAP;
709 if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
710 return (my_errno ? my_errno : -1);
711 if (!table->s->tmp_table) /* No need to perform a check for tmp table */
713 if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
715 /* purecov: begin inspected */
716 DBUG_PRINT("error", ("Failed to convert TABLE object to MyISAM "
717 "key and column definition"));
718 goto err;
719 /* purecov: end */
721 if (check_definition(keyinfo, recinfo, table->s->keys, recs,
722 file->s->keyinfo, file->s->rec,
723 file->s->base.keys, file->s->base.fields,
724 true, table))
726 /* purecov: begin inspected */
727 my_errno= HA_ERR_CRASHED;
728 goto err;
729 /* purecov: end */
733 if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
734 VOID(mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0));
736 info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
737 if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
738 VOID(mi_extra(file, HA_EXTRA_WAIT_LOCK, 0));
739 if (!table->s->db_record_offset)
740 int_table_flags|=HA_REC_NOT_IN_SEQ;
741 if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
742 int_table_flags|=HA_HAS_CHECKSUM;
744 for (i= 0; i < table->s->keys; i++)
746 plugin_ref parser= table->key_info[i].parser;
747 if (table->key_info[i].flags & HA_USES_PARSER)
748 file->s->keyinfo[i].parser=
749 (struct st_mysql_ftparser *)plugin_decl(parser)->info;
750 table->key_info[i].block_size= file->s->keyinfo[i].block_length;
752 my_errno= 0;
753 goto end;
754 err:
755 this->close();
756 end:
758 Both recinfo and keydef are allocated by my_multi_malloc(), thus only
759 recinfo must be freed.
761 if (recinfo)
762 my_free((uchar*) recinfo, MYF(0));
763 return my_errno;
766 int ha_myisam::close(void)
768 MI_INFO *tmp=file;
769 file=0;
770 return mi_close(tmp);
773 int ha_myisam::write_row(uchar *buf)
775 ha_statistic_increment(&SSV::ha_write_count);
777 /* If we have a timestamp column, update it to the current time */
778 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
779 table->timestamp_field->set_time();
782 If we have an auto_increment column and we are writing a changed row
783 or a new row, then update the auto_increment value in the record.
785 if (table->next_number_field && buf == table->record[0])
787 int error;
788 if ((error= update_auto_increment()))
789 return error;
791 return mi_write(file,buf);
794 int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
796 if (!file) return HA_ADMIN_INTERNAL_ERROR;
797 int error;
798 MI_CHECK param;
799 MYISAM_SHARE* share = file->s;
800 const char *old_proc_info=thd->proc_info;
802 thd_proc_info(thd, "Checking table");
803 myisamchk_init(&param);
804 param.thd = thd;
805 param.op_name = "check";
806 param.db_name= table->s->db.str;
807 param.table_name= table->alias;
808 param.testflag = check_opt->flags | T_CHECK | T_SILENT;
809 param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
811 if (!(table->db_stat & HA_READ_ONLY))
812 param.testflag|= T_STATISTICS;
813 param.using_global_keycache = 1;
815 if (!mi_is_crashed(file) &&
816 (((param.testflag & T_CHECK_ONLY_CHANGED) &&
817 !(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
818 STATE_CRASHED_ON_REPAIR)) &&
819 share->state.open_count == 0) ||
820 ((param.testflag & T_FAST) && (share->state.open_count ==
821 (uint) (share->global_changed ? 1 : 0)))))
822 return HA_ADMIN_ALREADY_DONE;
824 error = chk_status(&param, file); // Not fatal
825 error = chk_size(&param, file);
826 if (!error)
827 error |= chk_del(&param, file, param.testflag);
828 if (!error)
829 error = chk_key(&param, file);
830 if (!error)
832 if ((!(param.testflag & T_QUICK) &&
833 ((share->options &
834 (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
835 (param.testflag & (T_EXTEND | T_MEDIUM)))) ||
836 mi_is_crashed(file))
838 uint old_testflag=param.testflag;
839 param.testflag|=T_MEDIUM;
840 if (!(error= init_io_cache(&param.read_cache, file->dfile,
841 my_default_record_cache_size, READ_CACHE,
842 share->pack.header_length, 1, MYF(MY_WME))))
844 error= chk_data_link(&param, file, param.testflag & T_EXTEND);
845 end_io_cache(&(param.read_cache));
847 param.testflag= old_testflag;
850 if (!error)
852 if ((share->state.changed & (STATE_CHANGED |
853 STATE_CRASHED_ON_REPAIR |
854 STATE_CRASHED | STATE_NOT_ANALYZED)) ||
855 (param.testflag & T_STATISTICS) ||
856 mi_is_crashed(file))
858 file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
859 pthread_mutex_lock(&share->intern_lock);
860 share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
861 STATE_CRASHED_ON_REPAIR);
862 if (!(table->db_stat & HA_READ_ONLY))
863 error=update_state_info(&param,file,UPDATE_TIME | UPDATE_OPEN_COUNT |
864 UPDATE_STAT);
865 pthread_mutex_unlock(&share->intern_lock);
866 info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
867 HA_STATUS_CONST);
870 else if (!mi_is_crashed(file) && !thd->killed)
872 mi_mark_crashed(file);
873 file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
876 thd_proc_info(thd, old_proc_info);
877 return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
882 analyze the key distribution in the table
883 As the table may be only locked for read, we have to take into account that
884 two threads may do an analyze at the same time!
887 int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
889 int error=0;
890 MI_CHECK param;
891 MYISAM_SHARE* share = file->s;
893 myisamchk_init(&param);
894 param.thd = thd;
895 param.op_name= "analyze";
896 param.db_name= table->s->db.str;
897 param.table_name= table->alias;
898 param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
899 T_DONT_CHECK_CHECKSUM);
900 param.using_global_keycache = 1;
901 param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
903 if (!(share->state.changed & STATE_NOT_ANALYZED))
904 return HA_ADMIN_ALREADY_DONE;
906 error = chk_key(&param, file);
907 if (!error)
909 pthread_mutex_lock(&share->intern_lock);
910 error=update_state_info(&param,file,UPDATE_STAT);
911 pthread_mutex_unlock(&share->intern_lock);
913 else if (!mi_is_crashed(file) && !thd->killed)
914 mi_mark_crashed(file);
915 return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
919 int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
921 HA_CHECK_OPT tmp_check_opt;
922 char *backup_dir= thd->lex->backup_dir;
923 char src_path[FN_REFLEN], dst_path[FN_REFLEN];
924 char table_name[FN_REFLEN];
925 int error;
926 const char* errmsg;
927 DBUG_ENTER("restore");
929 VOID(tablename_to_filename(table->s->table_name.str, table_name,
930 sizeof(table_name)));
932 if (fn_format_relative_to_data_home(src_path, table_name, backup_dir,
933 MI_NAME_DEXT))
934 DBUG_RETURN(HA_ADMIN_INVALID);
936 strxmov(dst_path, table->s->normalized_path.str, MI_NAME_DEXT, NullS);
937 if (my_copy(src_path, dst_path, MYF(MY_WME)))
939 error= HA_ADMIN_FAILED;
940 errmsg= "Failed in my_copy (Error %d)";
941 goto err;
944 tmp_check_opt.init();
945 tmp_check_opt.flags |= T_VERY_SILENT | T_CALC_CHECKSUM | T_QUICK;
946 DBUG_RETURN(repair(thd, &tmp_check_opt));
948 err:
950 MI_CHECK param;
951 myisamchk_init(&param);
952 param.thd= thd;
953 param.op_name= "restore";
954 param.db_name= table->s->db.str;
955 param.table_name= table->s->table_name.str;
956 param.testflag= 0;
957 mi_check_print_error(&param, errmsg, my_errno);
958 DBUG_RETURN(error);
963 int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
965 char *backup_dir= thd->lex->backup_dir;
966 char src_path[FN_REFLEN], dst_path[FN_REFLEN];
967 char table_name[FN_REFLEN];
968 int error;
969 const char *errmsg;
970 DBUG_ENTER("ha_myisam::backup");
972 VOID(tablename_to_filename(table->s->table_name.str, table_name,
973 sizeof(table_name)));
975 if (fn_format_relative_to_data_home(dst_path, table_name, backup_dir,
976 reg_ext))
978 errmsg= "Failed in fn_format() for .frm file (errno: %d)";
979 error= HA_ADMIN_INVALID;
980 goto err;
983 strxmov(src_path, table->s->normalized_path.str, reg_ext, NullS);
984 if (my_copy(src_path, dst_path,
985 MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_DONT_OVERWRITE_FILE)))
987 error = HA_ADMIN_FAILED;
988 errmsg = "Failed copying .frm file (errno: %d)";
989 goto err;
992 /* Change extension */
993 if (fn_format_relative_to_data_home(dst_path, table_name, backup_dir,
994 MI_NAME_DEXT))
996 errmsg = "Failed in fn_format() for .MYD file (errno: %d)";
997 error = HA_ADMIN_INVALID;
998 goto err;
1001 strxmov(src_path, table->s->normalized_path.str, MI_NAME_DEXT, NullS);
1002 if (my_copy(src_path, dst_path,
1003 MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_DONT_OVERWRITE_FILE)))
1005 errmsg = "Failed copying .MYD file (errno: %d)";
1006 error= HA_ADMIN_FAILED;
1007 goto err;
1009 DBUG_RETURN(HA_ADMIN_OK);
1011 err:
1013 MI_CHECK param;
1014 myisamchk_init(&param);
1015 param.thd= thd;
1016 param.op_name= "backup";
1017 param.db_name= table->s->db.str;
1018 param.table_name= table->s->table_name.str;
1019 param.testflag = 0;
1020 mi_check_print_error(&param,errmsg, my_errno);
1021 DBUG_RETURN(error);
1026 int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
1028 int error;
1029 MI_CHECK param;
1030 ha_rows start_records;
1032 if (!file) return HA_ADMIN_INTERNAL_ERROR;
1034 myisamchk_init(&param);
1035 param.thd = thd;
1036 param.op_name= "repair";
1037 param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
1038 T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
1039 (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
1040 param.sort_buffer_length= check_opt->sort_buffer_size;
1041 start_records=file->state->records;
1042 while ((error=repair(thd,param,0)) && param.retry_repair)
1044 param.retry_repair=0;
1045 if (test_all_bits(param.testflag,
1046 (uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
1048 param.testflag&= ~T_RETRY_WITHOUT_QUICK;
1049 sql_print_information("Retrying repair of: '%s' without quick",
1050 table->s->path.str);
1051 continue;
1053 param.testflag&= ~T_QUICK;
1054 if ((param.testflag & T_REP_BY_SORT))
1056 param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
1057 sql_print_information("Retrying repair of: '%s' with keycache",
1058 table->s->path.str);
1059 continue;
1061 break;
1063 if (!error && start_records != file->state->records &&
1064 !(check_opt->flags & T_VERY_SILENT))
1066 char llbuff[22],llbuff2[22];
1067 sql_print_information("Found %s of %s rows when repairing '%s'",
1068 llstr(file->state->records, llbuff),
1069 llstr(start_records, llbuff2),
1070 table->s->path.str);
1072 return error;
1075 int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
1077 int error;
1078 if (!file) return HA_ADMIN_INTERNAL_ERROR;
1079 MI_CHECK param;
1081 myisamchk_init(&param);
1082 param.thd = thd;
1083 param.op_name= "optimize";
1084 param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
1085 T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
1086 param.sort_buffer_length= check_opt->sort_buffer_size;
1087 if ((error= repair(thd,param,1)) && param.retry_repair)
1089 sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying",
1090 my_errno, param.db_name, param.table_name);
1091 param.testflag&= ~T_REP_BY_SORT;
1092 error= repair(thd,param,1);
1094 return error;
1098 int ha_myisam::repair(THD *thd, MI_CHECK &param, bool do_optimize)
1100 int error=0;
1101 uint local_testflag=param.testflag;
1102 bool optimize_done= !do_optimize, statistics_done=0;
1103 const char *old_proc_info=thd->proc_info;
1104 char fixed_name[FN_REFLEN];
1105 MYISAM_SHARE* share = file->s;
1106 ha_rows rows= file->state->records;
1107 DBUG_ENTER("ha_myisam::repair");
1109 param.db_name= table->s->db.str;
1110 param.table_name= table->alias;
1111 param.tmpfile_createflag = O_RDWR | O_TRUNC;
1112 param.using_global_keycache = 1;
1113 param.thd= thd;
1114 param.tmpdir= &mysql_tmpdir_list;
1115 param.out_flag= 0;
1116 strmov(fixed_name,file->filename);
1118 // Release latches since this can take a long time
1119 ha_release_temporary_latches(thd);
1121 // Don't lock tables if we have used LOCK TABLE
1122 if (!thd->locked_tables &&
1123 mi_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK))
1125 mi_check_print_error(&param,ER(ER_CANT_LOCK),my_errno);
1126 DBUG_RETURN(HA_ADMIN_FAILED);
1129 if (!do_optimize ||
1130 ((file->state->del || share->state.split != file->state->records) &&
1131 (!(param.testflag & T_QUICK) ||
1132 !(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))))
1134 ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
1135 mi_get_mask_all_keys_active(share->base.keys) :
1136 share->state.key_map);
1137 uint testflag=param.testflag;
1138 #ifdef HAVE_MMAP
1139 bool remap= test(share->file_map);
1141 mi_repair*() functions family use file I/O even if memory
1142 mapping is available.
1144 Since mixing mmap I/O and file I/O may cause various artifacts,
1145 memory mapping must be disabled.
1147 if (remap)
1148 mi_munmap_file(file);
1149 #endif
1150 if (mi_test_if_sort_rep(file,file->state->records,key_map,0) &&
1151 (local_testflag & T_REP_BY_SORT))
1153 local_testflag|= T_STATISTICS;
1154 param.testflag|= T_STATISTICS; // We get this for free
1155 statistics_done=1;
1156 if (thd->variables.myisam_repair_threads>1)
1158 char buf[40];
1159 /* TODO: respect myisam_repair_threads variable */
1160 my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
1161 thd_proc_info(thd, buf);
1162 error = mi_repair_parallel(&param, file, fixed_name,
1163 param.testflag & T_QUICK);
1164 thd_proc_info(thd, "Repair done"); // to reset proc_info, as
1165 // it was pointing to local buffer
1167 else
1169 thd_proc_info(thd, "Repair by sorting");
1170 error = mi_repair_by_sort(&param, file, fixed_name,
1171 param.testflag & T_QUICK);
1174 else
1176 thd_proc_info(thd, "Repair with keycache");
1177 param.testflag &= ~T_REP_BY_SORT;
1178 error= mi_repair(&param, file, fixed_name,
1179 param.testflag & T_QUICK);
1181 #ifdef HAVE_MMAP
1182 if (remap)
1183 mi_dynmap_file(file, file->state->data_file_length);
1184 #endif
1185 param.testflag=testflag;
1186 optimize_done=1;
1188 if (!error)
1190 if ((local_testflag & T_SORT_INDEX) &&
1191 (share->state.changed & STATE_NOT_SORTED_PAGES))
1193 optimize_done=1;
1194 thd_proc_info(thd, "Sorting index");
1195 error=mi_sort_index(&param,file,fixed_name);
1197 if (!statistics_done && (local_testflag & T_STATISTICS))
1199 if (share->state.changed & STATE_NOT_ANALYZED)
1201 optimize_done=1;
1202 thd_proc_info(thd, "Analyzing");
1203 error = chk_key(&param, file);
1205 else
1206 local_testflag&= ~T_STATISTICS; // Don't update statistics
1209 thd_proc_info(thd, "Saving state");
1210 if (!error)
1212 if ((share->state.changed & STATE_CHANGED) || mi_is_crashed(file))
1214 share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1215 STATE_CRASHED_ON_REPAIR);
1216 file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1219 the following 'if', thought conceptually wrong,
1220 is a useful optimization nevertheless.
1222 if (file->state != &file->s->state.state)
1223 file->s->state.state = *file->state;
1224 if (file->s->base.auto_key)
1225 update_auto_increment_key(&param, file, 1);
1226 if (optimize_done)
1227 error = update_state_info(&param, file,
1228 UPDATE_TIME | UPDATE_OPEN_COUNT |
1229 (local_testflag &
1230 T_STATISTICS ? UPDATE_STAT : 0));
1231 info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
1232 HA_STATUS_CONST);
1233 if (rows != file->state->records && ! (param.testflag & T_VERY_SILENT))
1235 char llbuff[22],llbuff2[22];
1236 mi_check_print_warning(&param,"Number of rows changed from %s to %s",
1237 llstr(rows,llbuff),
1238 llstr(file->state->records,llbuff2));
1241 else
1243 mi_mark_crashed_on_repair(file);
1244 file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1245 update_state_info(&param, file, 0);
1247 thd_proc_info(thd, old_proc_info);
1248 if (!thd->locked_tables)
1249 mi_lock_database(file,F_UNLCK);
1250 DBUG_RETURN(error ? HA_ADMIN_FAILED :
1251 !optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
1256 Assign table indexes to a specific key cache.
1259 int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
1261 KEY_CACHE *new_key_cache= check_opt->key_cache;
1262 const char *errmsg= 0;
1263 int error= HA_ADMIN_OK;
1264 ulonglong map;
1265 TABLE_LIST *table_list= table->pos_in_table_list;
1266 DBUG_ENTER("ha_myisam::assign_to_keycache");
1268 table->keys_in_use_for_query.clear_all();
1270 if (table_list->process_index_hints(table))
1271 DBUG_RETURN(HA_ADMIN_FAILED);
1272 map= ~(ulonglong) 0;
1273 if (!table->keys_in_use_for_query.is_clear_all())
1274 /* use all keys if there's no list specified by the user through hints */
1275 map= table->keys_in_use_for_query.to_ulonglong();
1277 if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
1279 char buf[STRING_BUFFER_USUAL_SIZE];
1280 my_snprintf(buf, sizeof(buf),
1281 "Failed to flush to index file (errno: %d)", error);
1282 errmsg= buf;
1283 error= HA_ADMIN_CORRUPT;
1286 if (error != HA_ADMIN_OK)
1288 /* Send error to user */
1289 MI_CHECK param;
1290 myisamchk_init(&param);
1291 param.thd= thd;
1292 param.op_name= "assign_to_keycache";
1293 param.db_name= table->s->db.str;
1294 param.table_name= table->s->table_name.str;
1295 param.testflag= 0;
1296 mi_check_print_error(&param, errmsg);
1298 DBUG_RETURN(error);
1303 Preload pages of the index file for a table into the key cache.
1306 int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
1308 int error;
1309 const char *errmsg;
1310 ulonglong map;
1311 TABLE_LIST *table_list= table->pos_in_table_list;
1312 my_bool ignore_leaves= table_list->ignore_leaves;
1313 char buf[MYSQL_ERRMSG_SIZE];
1315 DBUG_ENTER("ha_myisam::preload_keys");
1317 table->keys_in_use_for_query.clear_all();
1319 if (table_list->process_index_hints(table))
1320 DBUG_RETURN(HA_ADMIN_FAILED);
1322 map= ~(ulonglong) 0;
1323 /* Check validity of the index references */
1324 if (!table->keys_in_use_for_query.is_clear_all())
1325 /* use all keys if there's no list specified by the user through hints */
1326 map= table->keys_in_use_for_query.to_ulonglong();
1328 mi_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE,
1329 (void *) &thd->variables.preload_buff_size);
1331 if ((error= mi_preload(file, map, ignore_leaves)))
1333 switch (error) {
1334 case HA_ERR_NON_UNIQUE_BLOCK_SIZE:
1335 errmsg= "Indexes use different block sizes";
1336 break;
1337 case HA_ERR_OUT_OF_MEM:
1338 errmsg= "Failed to allocate buffer";
1339 break;
1340 default:
1341 my_snprintf(buf, sizeof(buf),
1342 "Failed to read from index file (errno: %d)", my_errno);
1343 errmsg= buf;
1345 error= HA_ADMIN_FAILED;
1346 goto err;
1349 DBUG_RETURN(HA_ADMIN_OK);
1351 err:
1353 MI_CHECK param;
1354 myisamchk_init(&param);
1355 param.thd= thd;
1356 param.op_name= "preload_keys";
1357 param.db_name= table->s->db.str;
1358 param.table_name= table->s->table_name.str;
1359 param.testflag= 0;
1360 mi_check_print_error(&param, errmsg);
1361 DBUG_RETURN(error);
1367 Disable indexes, making it persistent if requested.
1369 SYNOPSIS
1370 disable_indexes()
1371 mode mode of operation:
1372 HA_KEY_SWITCH_NONUNIQ disable all non-unique keys
1373 HA_KEY_SWITCH_ALL disable all keys
1374 HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
1375 HA_KEY_SWITCH_ALL_SAVE dis. all keys and make persistent
1377 IMPLEMENTATION
1378 HA_KEY_SWITCH_NONUNIQ is not implemented.
1379 HA_KEY_SWITCH_ALL_SAVE is not implemented.
1381 RETURN
1382 0 ok
1383 HA_ERR_WRONG_COMMAND mode not implemented.
1386 int ha_myisam::disable_indexes(uint mode)
1388 int error;
1390 if (mode == HA_KEY_SWITCH_ALL)
1392 /* call a storage engine function to switch the key map */
1393 error= mi_disable_indexes(file);
1395 else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
1397 mi_extra(file, HA_EXTRA_NO_KEYS, 0);
1398 info(HA_STATUS_CONST); // Read new key info
1399 error= 0;
1401 else
1403 /* mode not implemented */
1404 error= HA_ERR_WRONG_COMMAND;
1406 return error;
1411 Enable indexes, making it persistent if requested.
1413 SYNOPSIS
1414 enable_indexes()
1415 mode mode of operation:
1416 HA_KEY_SWITCH_NONUNIQ enable all non-unique keys
1417 HA_KEY_SWITCH_ALL enable all keys
1418 HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
1419 HA_KEY_SWITCH_ALL_SAVE en. all keys and make persistent
1421 DESCRIPTION
1422 Enable indexes, which might have been disabled by disable_index() before.
1423 The modes without _SAVE work only if both data and indexes are empty,
1424 since the MyISAM repair would enable them persistently.
1425 To be sure in these cases, call handler::delete_all_rows() before.
1427 IMPLEMENTATION
1428 HA_KEY_SWITCH_NONUNIQ is not implemented.
1429 HA_KEY_SWITCH_ALL_SAVE is not implemented.
1431 RETURN
1432 0 ok
1433 !=0 Error, among others:
1434 HA_ERR_CRASHED data or index is non-empty. Delete all rows and retry.
1435 HA_ERR_WRONG_COMMAND mode not implemented.
1438 int ha_myisam::enable_indexes(uint mode)
1440 int error;
1442 DBUG_EXECUTE_IF("wait_in_enable_indexes",
1443 debug_wait_for_kill("wait_in_enable_indexes"); );
1445 if (mi_is_all_keys_active(file->s->state.key_map, file->s->base.keys))
1447 /* All indexes are enabled already. */
1448 return 0;
1451 if (mode == HA_KEY_SWITCH_ALL)
1453 error= mi_enable_indexes(file);
1455 Do not try to repair on error,
1456 as this could make the enabled state persistent,
1457 but mode==HA_KEY_SWITCH_ALL forbids it.
1460 else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
1462 THD *thd=current_thd;
1463 MI_CHECK param;
1464 const char *save_proc_info=thd->proc_info;
1465 thd_proc_info(thd, "Creating index");
1466 myisamchk_init(&param);
1467 param.op_name= "recreating_index";
1468 param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
1469 T_CREATE_MISSING_KEYS);
1470 param.myf_rw&= ~MY_WAIT_IF_FULL;
1471 param.sort_buffer_length= thd->variables.myisam_sort_buff_size;
1472 param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
1473 param.tmpdir=&mysql_tmpdir_list;
1474 if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair)
1476 sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, retrying",
1477 my_errno, param.db_name, param.table_name);
1479 Repairing by sort failed. Now try standard repair method.
1480 Still we want to fix only index file. If data file corruption
1481 was detected (T_RETRY_WITHOUT_QUICK), we shouldn't do much here.
1482 Let implicit repair do this job.
1484 if (!(param.testflag & T_RETRY_WITHOUT_QUICK))
1486 param.testflag&= ~T_REP_BY_SORT;
1487 error= (repair(thd,param,0) != HA_ADMIN_OK);
1490 If the standard repair succeeded, clear all error messages which
1491 might have been set by the first repair. They can still be seen
1492 with SHOW WARNINGS then.
1494 if (! error)
1495 thd->clear_error();
1497 info(HA_STATUS_CONST);
1498 thd_proc_info(thd, save_proc_info);
1500 else
1502 /* mode not implemented */
1503 error= HA_ERR_WRONG_COMMAND;
1505 return error;
1510 Test if indexes are disabled.
1513 SYNOPSIS
1514 indexes_are_disabled()
1515 no parameters
1518 RETURN
1519 0 indexes are not disabled
1520 1 all indexes are disabled
1521 [2 non-unique indexes are disabled - NOT YET IMPLEMENTED]
1524 int ha_myisam::indexes_are_disabled(void)
1527 return mi_indexes_are_disabled(file);
1532 prepare for a many-rows insert operation
1533 e.g. - disable indexes (if they can be recreated fast) or
1534 activate special bulk-insert optimizations
1536 SYNOPSIS
1537 start_bulk_insert(rows)
1538 rows Rows to be inserted
1539 0 if we don't know
1541 NOTICE
1542 Do not forget to call end_bulk_insert() later!
1545 void ha_myisam::start_bulk_insert(ha_rows rows)
1547 DBUG_ENTER("ha_myisam::start_bulk_insert");
1548 THD *thd= current_thd;
1549 ulong size= min(thd->variables.read_buff_size,
1550 (ulong) (table->s->avg_row_length*rows));
1551 DBUG_PRINT("info",("start_bulk_insert: rows %lu size %lu",
1552 (ulong) rows, size));
1554 /* don't enable row cache if too few rows */
1555 if (! rows || (rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE))
1556 mi_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &size);
1558 can_enable_indexes= mi_is_all_keys_active(file->s->state.key_map,
1559 file->s->base.keys);
1561 if (!(specialflag & SPECIAL_SAFE_MODE))
1564 Only disable old index if the table was empty and we are inserting
1565 a lot of rows.
1566 Note that in end_bulk_insert() we may truncate the table if
1567 enable_indexes() failed, thus it's essential that indexes are
1568 disabled ONLY for an empty table.
1570 if (file->state->records == 0 && can_enable_indexes &&
1571 (!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES))
1572 mi_disable_non_unique_index(file,rows);
1573 else
1574 if (!file->bulk_insert &&
1575 (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT))
1577 mi_init_bulk_insert(file, thd->variables.bulk_insert_buff_size, rows);
1580 DBUG_VOID_RETURN;
1584 end special bulk-insert optimizations,
1585 which have been activated by start_bulk_insert().
1587 SYNOPSIS
1588 end_bulk_insert()
1589 no arguments
1591 RETURN
1592 0 OK
1593 != 0 Error
1596 int ha_myisam::end_bulk_insert()
1598 mi_end_bulk_insert(file);
1599 int err=mi_extra(file, HA_EXTRA_NO_CACHE, 0);
1600 if (!err)
1602 if (can_enable_indexes)
1605 Truncate the table when enable index operation is killed.
1606 After truncating the table we don't need to enable the
1607 indexes, because the last repair operation is aborted after
1608 setting the indexes as active and trying to recreate them.
1611 if (((err= enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE)) != 0) &&
1612 current_thd->killed)
1614 delete_all_rows();
1615 /* not crashed, despite being killed during repair */
1616 file->s->state.changed&= ~(STATE_CRASHED|STATE_CRASHED_ON_REPAIR);
1620 return err;
1624 bool ha_myisam::check_and_repair(THD *thd)
1626 int error=0;
1627 int marked_crashed;
1628 char *old_query;
1629 uint old_query_length;
1630 HA_CHECK_OPT check_opt;
1631 DBUG_ENTER("ha_myisam::check_and_repair");
1633 check_opt.init();
1634 check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
1635 // Don't use quick if deleted rows
1636 if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
1637 check_opt.flags|=T_QUICK;
1638 sql_print_warning("Checking table: '%s'",table->s->path.str);
1640 old_query= thd->query();
1641 old_query_length= thd->query_length();
1642 thd->set_query(table->s->table_name.str,
1643 (uint) table->s->table_name.length);
1645 if ((marked_crashed= mi_is_crashed(file)) || check(thd, &check_opt))
1647 sql_print_warning("Recovering table: '%s'",table->s->path.str);
1648 check_opt.flags=
1649 ((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
1650 (marked_crashed ? 0 : T_QUICK) |
1651 (myisam_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
1652 T_AUTO_REPAIR);
1653 if (repair(thd, &check_opt))
1654 error=1;
1656 thd->set_query(old_query, old_query_length);
1657 DBUG_RETURN(error);
1660 bool ha_myisam::is_crashed() const
1662 return (file->s->state.changed & STATE_CRASHED ||
1663 (my_disable_locking && file->s->state.open_count));
1666 int ha_myisam::update_row(const uchar *old_data, uchar *new_data)
1668 ha_statistic_increment(&SSV::ha_update_count);
1669 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
1670 table->timestamp_field->set_time();
1671 return mi_update(file,old_data,new_data);
1674 int ha_myisam::delete_row(const uchar *buf)
1676 ha_statistic_increment(&SSV::ha_delete_count);
1677 return mi_delete(file,buf);
1680 int ha_myisam::index_read_map(uchar *buf, const uchar *key,
1681 key_part_map keypart_map,
1682 enum ha_rkey_function find_flag)
1684 DBUG_ASSERT(inited==INDEX);
1685 ha_statistic_increment(&SSV::ha_read_key_count);
1686 int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
1687 table->status=error ? STATUS_NOT_FOUND: 0;
1688 return error;
1691 int ha_myisam::index_read_idx_map(uchar *buf, uint index, const uchar *key,
1692 key_part_map keypart_map,
1693 enum ha_rkey_function find_flag)
1695 ha_statistic_increment(&SSV::ha_read_key_count);
1696 int error=mi_rkey(file, buf, index, key, keypart_map, find_flag);
1697 table->status=error ? STATUS_NOT_FOUND: 0;
1698 return error;
1701 int ha_myisam::index_read_last_map(uchar *buf, const uchar *key,
1702 key_part_map keypart_map)
1704 DBUG_ENTER("ha_myisam::index_read_last");
1705 DBUG_ASSERT(inited==INDEX);
1706 ha_statistic_increment(&SSV::ha_read_key_count);
1707 int error=mi_rkey(file, buf, active_index, key, keypart_map,
1708 HA_READ_PREFIX_LAST);
1709 table->status=error ? STATUS_NOT_FOUND: 0;
1710 DBUG_RETURN(error);
1713 int ha_myisam::index_next(uchar *buf)
1715 DBUG_ASSERT(inited==INDEX);
1716 ha_statistic_increment(&SSV::ha_read_next_count);
1717 int error=mi_rnext(file,buf,active_index);
1718 table->status=error ? STATUS_NOT_FOUND: 0;
1719 return error;
1722 int ha_myisam::index_prev(uchar *buf)
1724 DBUG_ASSERT(inited==INDEX);
1725 ha_statistic_increment(&SSV::ha_read_prev_count);
1726 int error=mi_rprev(file,buf, active_index);
1727 table->status=error ? STATUS_NOT_FOUND: 0;
1728 return error;
1731 int ha_myisam::index_first(uchar *buf)
1733 DBUG_ASSERT(inited==INDEX);
1734 ha_statistic_increment(&SSV::ha_read_first_count);
1735 int error=mi_rfirst(file, buf, active_index);
1736 table->status=error ? STATUS_NOT_FOUND: 0;
1737 return error;
1740 int ha_myisam::index_last(uchar *buf)
1742 DBUG_ASSERT(inited==INDEX);
1743 ha_statistic_increment(&SSV::ha_read_last_count);
1744 int error=mi_rlast(file, buf, active_index);
1745 table->status=error ? STATUS_NOT_FOUND: 0;
1746 return error;
1749 int ha_myisam::index_next_same(uchar *buf,
1750 const uchar *key __attribute__((unused)),
1751 uint length __attribute__((unused)))
1753 int error;
1754 DBUG_ASSERT(inited==INDEX);
1755 ha_statistic_increment(&SSV::ha_read_next_count);
1758 error= mi_rnext_same(file,buf);
1759 } while (error == HA_ERR_RECORD_DELETED);
1760 table->status=error ? STATUS_NOT_FOUND: 0;
1761 return error;
1765 int ha_myisam::rnd_init(bool scan)
1767 if (scan)
1768 return mi_scan_init(file);
1769 return mi_reset(file); // Free buffers
1772 int ha_myisam::rnd_next(uchar *buf)
1774 ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1775 int error=mi_scan(file, buf);
1776 table->status=error ? STATUS_NOT_FOUND: 0;
1777 return error;
1780 int ha_myisam::restart_rnd_next(uchar *buf, uchar *pos)
1782 return rnd_pos(buf,pos);
1785 int ha_myisam::rnd_pos(uchar *buf, uchar *pos)
1787 ha_statistic_increment(&SSV::ha_read_rnd_count);
1788 int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
1789 table->status=error ? STATUS_NOT_FOUND: 0;
1790 return error;
1793 void ha_myisam::position(const uchar *record)
1795 my_off_t row_position= mi_position(file);
1796 my_store_ptr(ref, ref_length, row_position);
1799 int ha_myisam::info(uint flag)
1801 MI_ISAMINFO misam_info;
1802 char name_buff[FN_REFLEN];
1804 (void) mi_status(file,&misam_info,flag);
1805 if (flag & HA_STATUS_VARIABLE)
1807 stats.records= misam_info.records;
1808 stats.deleted= misam_info.deleted;
1809 stats.data_file_length= misam_info.data_file_length;
1810 stats.index_file_length= misam_info.index_file_length;
1811 stats.delete_length= misam_info.delete_length;
1812 stats.check_time= (ulong) misam_info.check_time;
1813 stats.mean_rec_length= misam_info.mean_reclength;
1815 if (flag & HA_STATUS_CONST)
1817 TABLE_SHARE *share= table->s;
1818 stats.max_data_file_length= misam_info.max_data_file_length;
1819 stats.max_index_file_length= misam_info.max_index_file_length;
1820 stats.create_time= (ulong) misam_info.create_time;
1821 ref_length= misam_info.reflength;
1822 share->db_options_in_use= misam_info.options;
1823 stats.block_size= myisam_block_size; /* record block size */
1825 /* Update share */
1826 if (share->tmp_table == NO_TMP_TABLE)
1827 pthread_mutex_lock(&share->mutex);
1828 share->keys_in_use.set_prefix(share->keys);
1829 share->keys_in_use.intersect_extended(misam_info.key_map);
1830 share->keys_for_keyread.intersect(share->keys_in_use);
1831 share->db_record_offset= misam_info.record_offset;
1832 if (share->key_parts)
1833 memcpy((char*) table->key_info[0].rec_per_key,
1834 (char*) misam_info.rec_per_key,
1835 sizeof(table->key_info[0].rec_per_key[0])*share->key_parts);
1836 if (share->tmp_table == NO_TMP_TABLE)
1837 pthread_mutex_unlock(&share->mutex);
1840 Set data_file_name and index_file_name to point at the symlink value
1841 if table is symlinked (Ie; Real name is not same as generated name)
1843 data_file_name= index_file_name= 0;
1844 fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1845 MY_APPEND_EXT | MY_UNPACK_FILENAME);
1846 if (strcmp(name_buff, misam_info.data_file_name))
1847 data_file_name=misam_info.data_file_name;
1848 fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1849 MY_APPEND_EXT | MY_UNPACK_FILENAME);
1850 if (strcmp(name_buff, misam_info.index_file_name))
1851 index_file_name=misam_info.index_file_name;
1853 if (flag & HA_STATUS_ERRKEY)
1855 errkey = misam_info.errkey;
1856 my_store_ptr(dup_ref, ref_length, misam_info.dupp_key_pos);
1858 if (flag & HA_STATUS_TIME)
1859 stats.update_time = (ulong) misam_info.update_time;
1860 if (flag & HA_STATUS_AUTO)
1861 stats.auto_increment_value= misam_info.auto_increment;
1863 return 0;
1867 int ha_myisam::extra(enum ha_extra_function operation)
1869 if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_KEYREAD)
1870 return 0;
1871 if (operation == HA_EXTRA_MMAP && !opt_myisam_use_mmap)
1872 return 0;
1873 return mi_extra(file, operation, 0);
1876 int ha_myisam::reset(void)
1878 return mi_reset(file);
1881 /* To be used with WRITE_CACHE and EXTRA_CACHE */
1883 int ha_myisam::extra_opt(enum ha_extra_function operation, ulong cache_size)
1885 if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE)
1886 return 0;
1887 return mi_extra(file, operation, (void*) &cache_size);
1890 int ha_myisam::delete_all_rows()
1892 return mi_delete_all_rows(file);
1895 int ha_myisam::reset_auto_increment(ulonglong value)
1897 file->s->state.auto_increment= value;
1898 return 0;
1901 int ha_myisam::delete_table(const char *name)
1903 return mi_delete_table(name);
1907 int ha_myisam::external_lock(THD *thd, int lock_type)
1909 return mi_lock_database(file, !table->s->tmp_table ?
1910 lock_type : ((lock_type == F_UNLCK) ?
1911 F_UNLCK : F_EXTRA_LCK));
1914 THR_LOCK_DATA **ha_myisam::store_lock(THD *thd,
1915 THR_LOCK_DATA **to,
1916 enum thr_lock_type lock_type)
1918 if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
1919 file->lock.type=lock_type;
1920 *to++= &file->lock;
1921 return to;
1924 void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
1926 ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
1927 if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
1929 create_info->auto_increment_value= stats.auto_increment_value;
1931 create_info->data_file_name=data_file_name;
1932 create_info->index_file_name=index_file_name;
1936 int ha_myisam::create(const char *name, register TABLE *table_arg,
1937 HA_CREATE_INFO *ha_create_info)
1939 int error;
1940 uint create_flags= 0, records, i;
1941 char buff[FN_REFLEN];
1942 MI_KEYDEF *keydef;
1943 MI_COLUMNDEF *recinfo;
1944 MI_CREATE_INFO create_info;
1945 TABLE_SHARE *share= table_arg->s;
1946 uint options= share->db_options_in_use;
1947 DBUG_ENTER("ha_myisam::create");
1948 for (i= 0; i < share->keys; i++)
1950 if (table_arg->key_info[i].flags & HA_USES_PARSER)
1952 create_flags|= HA_CREATE_RELIES_ON_SQL_LAYER;
1953 break;
1956 if ((error= table2myisam(table_arg, &keydef, &recinfo, &records)))
1957 DBUG_RETURN(error); /* purecov: inspected */
1958 bzero((char*) &create_info, sizeof(create_info));
1959 create_info.max_rows= share->max_rows;
1960 create_info.reloc_rows= share->min_rows;
1961 create_info.with_auto_increment= share->next_number_key_offset == 0;
1962 create_info.auto_increment= (ha_create_info->auto_increment_value ?
1963 ha_create_info->auto_increment_value -1 :
1964 (ulonglong) 0);
1965 create_info.data_file_length= ((ulonglong) share->max_rows *
1966 share->avg_row_length);
1967 create_info.data_file_name= ha_create_info->data_file_name;
1968 create_info.index_file_name= ha_create_info->index_file_name;
1969 create_info.language= share->table_charset->number;
1971 if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
1972 create_flags|= HA_CREATE_TMP_TABLE;
1973 if (ha_create_info->options & HA_CREATE_KEEP_FILES)
1974 create_flags|= HA_CREATE_KEEP_FILES;
1975 if (options & HA_OPTION_PACK_RECORD)
1976 create_flags|= HA_PACK_RECORD;
1977 if (options & HA_OPTION_CHECKSUM)
1978 create_flags|= HA_CREATE_CHECKSUM;
1979 if (options & HA_OPTION_DELAY_KEY_WRITE)
1980 create_flags|= HA_CREATE_DELAY_KEY_WRITE;
1982 /* TODO: Check that the following fn_format is really needed */
1983 error= mi_create(fn_format(buff, name, "", "",
1984 MY_UNPACK_FILENAME|MY_APPEND_EXT),
1985 share->keys, keydef,
1986 records, recinfo,
1987 0, (MI_UNIQUEDEF*) 0,
1988 &create_info, create_flags);
1989 my_free((uchar*) recinfo, MYF(0));
1990 DBUG_RETURN(error);
1994 int ha_myisam::rename_table(const char * from, const char * to)
1996 return mi_rename(from,to);
2000 void ha_myisam::get_auto_increment(ulonglong offset, ulonglong increment,
2001 ulonglong nb_desired_values,
2002 ulonglong *first_value,
2003 ulonglong *nb_reserved_values)
2005 ulonglong nr;
2006 int error;
2007 uchar key[MI_MAX_KEY_LENGTH];
2009 if (!table->s->next_number_key_offset)
2010 { // Autoincrement at key-start
2011 ha_myisam::info(HA_STATUS_AUTO);
2012 *first_value= stats.auto_increment_value;
2013 /* MyISAM has only table-level lock, so reserves to +inf */
2014 *nb_reserved_values= ULONGLONG_MAX;
2015 return;
2018 /* it's safe to call the following if bulk_insert isn't on */
2019 mi_flush_bulk_insert(file, table->s->next_number_index);
2021 (void) extra(HA_EXTRA_KEYREAD);
2022 key_copy(key, table->record[0],
2023 table->key_info + table->s->next_number_index,
2024 table->s->next_number_key_offset);
2025 error= mi_rkey(file, table->record[1], (int) table->s->next_number_index,
2026 key, make_prev_keypart_map(table->s->next_number_keypart),
2027 HA_READ_PREFIX_LAST);
2028 if (error)
2029 nr= 1;
2030 else
2032 /* Get data from record[1] */
2033 nr= ((ulonglong) table->next_number_field->
2034 val_int_offset(table->s->rec_buff_length)+1);
2036 extra(HA_EXTRA_NO_KEYREAD);
2037 *first_value= nr;
2039 MySQL needs to call us for next row: assume we are inserting ("a",null)
2040 here, we return 3, and next this statement will want to insert ("b",null):
2041 there is no reason why ("b",3+1) would be the good row to insert: maybe it
2042 already exists, maybe 3+1 is too large...
2044 *nb_reserved_values= 1;
2049 Find out how many rows there is in the given range
2051 SYNOPSIS
2052 records_in_range()
2053 inx Index to use
2054 min_key Start of range. Null pointer if from first key
2055 max_key End of range. Null pointer if to last key
2057 NOTES
2058 min_key.flag can have one of the following values:
2059 HA_READ_KEY_EXACT Include the key in the range
2060 HA_READ_AFTER_KEY Don't include key in range
2062 max_key.flag can have one of the following values:
2063 HA_READ_BEFORE_KEY Don't include key in range
2064 HA_READ_AFTER_KEY Include all 'end_key' values in the range
2066 RETURN
2067 HA_POS_ERROR Something is wrong with the index tree.
2068 0 There is no matching keys in the given range
2069 number > 0 There is approximately 'number' matching rows in
2070 the range.
2073 ha_rows ha_myisam::records_in_range(uint inx, key_range *min_key,
2074 key_range *max_key)
2076 return (ha_rows) mi_records_in_range(file, (int) inx, min_key, max_key);
2080 int ha_myisam::ft_read(uchar *buf)
2082 int error;
2084 if (!ft_handler)
2085 return -1;
2087 thread_safe_increment(table->in_use->status_var.ha_read_next_count,
2088 &LOCK_status); // why ?
2090 error=ft_handler->please->read_next(ft_handler,(char*) buf);
2092 table->status=error ? STATUS_NOT_FOUND: 0;
2093 return error;
2096 uint ha_myisam::checksum() const
2098 return (uint)file->state->checksum;
2102 bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
2103 uint table_changes)
2105 uint options= table->s->db_options_in_use;
2107 if (info->auto_increment_value != stats.auto_increment_value ||
2108 info->data_file_name != data_file_name ||
2109 info->index_file_name != index_file_name ||
2110 table_changes == IS_EQUAL_NO ||
2111 table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
2112 return COMPATIBLE_DATA_NO;
2114 if ((options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
2115 HA_OPTION_DELAY_KEY_WRITE)) !=
2116 (info->table_options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
2117 HA_OPTION_DELAY_KEY_WRITE)))
2118 return COMPATIBLE_DATA_NO;
2119 return COMPATIBLE_DATA_YES;
2122 extern int mi_panic(enum ha_panic_function flag);
2123 int myisam_panic(handlerton *hton, ha_panic_function flag)
2125 return mi_panic(flag);
2128 static int myisam_init(void *p)
2130 handlerton *myisam_hton;
2132 myisam_hton= (handlerton *)p;
2133 myisam_hton->state= SHOW_OPTION_YES;
2134 myisam_hton->db_type= DB_TYPE_MYISAM;
2135 myisam_hton->create= myisam_create_handler;
2136 myisam_hton->panic= myisam_panic;
2137 myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
2138 return 0;
2141 struct st_mysql_storage_engine myisam_storage_engine=
2142 { MYSQL_HANDLERTON_INTERFACE_VERSION };
2144 mysql_declare_plugin(myisam)
2146 MYSQL_STORAGE_ENGINE_PLUGIN,
2147 &myisam_storage_engine,
2148 "MyISAM",
2149 "MySQL AB",
2150 "Default engine as of MySQL 3.23 with great performance",
2151 PLUGIN_LICENSE_GPL,
2152 myisam_init, /* Plugin Init */
2153 NULL, /* Plugin Deinit */
2154 0x0100, /* 1.0 */
2155 NULL, /* status variables */
2156 NULL, /* system variables */
2157 NULL /* config options */
2159 mysql_declare_plugin_end;
2162 #ifdef HAVE_QUERY_CACHE
2164 @brief Register a named table with a call back function to the query cache.
2166 @param thd The thread handle
2167 @param table_key A pointer to the table name in the table cache
2168 @param key_length The length of the table name
2169 @param[out] engine_callback The pointer to the storage engine call back
2170 function, currently 0
2171 @param[out] engine_data Engine data will be set to 0.
2173 @note Despite the name of this function, it is used to check each statement
2174 before it is cached and not to register a table or callback function.
2176 @see handler::register_query_cache_table
2178 @return The error code. The engine_data and engine_callback will be set to 0.
2179 @retval TRUE Success
2180 @retval FALSE An error occured
2183 my_bool ha_myisam::register_query_cache_table(THD *thd, char *table_name,
2184 uint table_name_len,
2185 qc_engine_callback
2186 *engine_callback,
2187 ulonglong *engine_data)
2189 DBUG_ENTER("ha_myisam::register_query_cache_table");
2191 No call back function is needed to determine if a cached statement
2192 is valid or not.
2194 *engine_callback= 0;
2197 No engine data is needed.
2199 *engine_data= 0;
2201 if (file->s->concurrent_insert)
2204 If a concurrent INSERT has happened just before the currently
2205 processed SELECT statement, the total size of the table is
2206 unknown.
2208 To determine if the table size is known, the current thread's snap
2209 shot of the table size with the actual table size are compared.
2211 If the table size is unknown the SELECT statement can't be cached.
2213 When concurrent inserts are disabled at table open, mi_open()
2214 does not assign a get_status() function. In this case the local
2215 ("current") status is never updated. We would wrongly think that
2216 we cannot cache the statement.
2218 ulonglong actual_data_file_length;
2219 ulonglong current_data_file_length;
2222 POSIX visibility rules specify that "2. Whatever memory values a
2223 thread can see when it unlocks a mutex <...> can also be seen by any
2224 thread that later locks the same mutex". In this particular case,
2225 concurrent insert thread had modified the data_file_length in
2226 MYISAM_SHARE before it has unlocked (or even locked)
2227 structure_guard_mutex. So, here we're guaranteed to see at least that
2228 value after we've locked the same mutex. We can see a later value
2229 (modified by some other thread) though, but it's ok, as we only want
2230 to know if the variable was changed, the actual new value doesn't matter
2232 actual_data_file_length= file->s->state.state.data_file_length;
2233 current_data_file_length= file->save_state.data_file_length;
2235 if (current_data_file_length != actual_data_file_length)
2237 /* Don't cache current statement. */
2238 DBUG_RETURN(FALSE);
2243 This query execution might have started after the query cache was flushed
2244 by a concurrent INSERT. In this case, don't cache this statement as the
2245 data file length difference might not be visible yet if the tables haven't
2246 been unlocked by the concurrent insert thread.
2248 if (file->state->uncacheable)
2249 DBUG_RETURN(FALSE);
2251 /* It is ok to try to cache current statement. */
2252 DBUG_RETURN(TRUE);
2254 #endif