1
/* Copyright (C) 2000-2006 MySQL AB
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
#ifdef USE_PRAGMA_IMPLEMENTATION
18
#pragma implementation // gcc: Class implementation
21
#define MYSQL_SERVER 1
22
#include "mysql_priv.h"
23
#include <mysql/plugin.h>
26
#include <myisampack.h>
27
#include "ha_myisam.h"
29
#include "myisamdef.h"
32
ulong myisam_recover_options= HA_RECOVER_NONE;
34
/* bits in myisam_recover_options */
35
const char *myisam_recover_names[] =
36
{ "DEFAULT", "BACKUP", "FORCE", "QUICK", NullS};
37
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
38
myisam_recover_names, NULL};
40
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
41
"nulls_ignored", NullS};
42
TYPELIB myisam_stats_method_typelib= {
43
array_elements(myisam_stats_method_names) - 1, "",
44
myisam_stats_method_names, NULL};
47
/*****************************************************************************
49
*****************************************************************************/
51
static handler *myisam_create_handler(handlerton *hton,
55
return new (mem_root) ha_myisam(hton, table);
58
// collect errors printed by mi_check routines
60
static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
61
const char *fmt, va_list args)
63
THD* thd = (THD*)param->thd;
64
Protocol *protocol= thd->protocol;
65
uint length, msg_length;
66
char msgbuf[MI_MAX_MSG_BUF];
67
char name[NAME_LEN*2+2];
69
msg_length= my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
70
msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
72
DBUG_PRINT(msg_type,("message: %s",msgbuf));
76
sql_print_error(msgbuf);
80
if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
83
my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
86
length=(uint) (strxmov(name, param->db_name,".",param->table_name,NullS) -
89
TODO: switch from protocol to push_warning here. The main reason we didn't
90
it yet is parallel repair. Due to following trace:
91
mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
93
Also we likely need to lock mutex here (in both cases with protocol and
96
protocol->prepare_for_resend();
97
protocol->store(name, length, system_charset_info);
98
protocol->store(param->op_name, system_charset_info);
99
protocol->store(msg_type, system_charset_info);
100
protocol->store(msgbuf, msg_length, system_charset_info);
101
if (protocol->write())
102
sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
109
Convert TABLE object to MyISAM key and column definition
113
table_arg in TABLE object.
114
keydef_out out MyISAM key definition.
115
recinfo_out out MyISAM column definition.
116
records_out out Number of fields.
119
This function will allocate and initialize MyISAM key and column
120
definition for further use in mi_create or for a check for underlying
121
table conformance in merge engine.
123
The caller needs to free *recinfo_out after use. Since *recinfo_out
124
and *keydef_out are allocated with a my_multi_malloc, *keydef_out
125
is freed automatically when *recinfo_out is freed.
132
int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
133
MI_COLUMNDEF **recinfo_out, uint *records_out)
135
uint i, j, recpos, minpos, fieldpos, temp_length, length;
136
enum ha_base_keytype type= HA_KEYTYPE_BINARY;
140
MI_COLUMNDEF *recinfo, *recinfo_pos;
142
TABLE_SHARE *share= table_arg->s;
143
uint options= share->db_options_in_use;
144
DBUG_ENTER("table2myisam");
145
if (!(my_multi_malloc(MYF(MY_WME),
146
recinfo_out, (share->fields * 2 + 2) * sizeof(MI_COLUMNDEF),
147
keydef_out, share->keys * sizeof(MI_KEYDEF),
149
(share->key_parts + share->keys) * sizeof(HA_KEYSEG),
151
DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
153
recinfo= *recinfo_out;
154
pos= table_arg->key_info;
155
for (i= 0; i < share->keys; i++, pos++)
157
keydef[i].flag= ((uint16) pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL));
158
keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ?
159
(pos->flags & HA_SPATIAL ? HA_KEY_ALG_RTREE : HA_KEY_ALG_BTREE) :
161
keydef[i].block_length= pos->block_size;
162
keydef[i].seg= keyseg;
163
keydef[i].keysegs= pos->key_parts;
164
for (j= 0; j < pos->key_parts; j++)
166
Field *field= pos->key_part[j].field;
167
type= field->key_type();
168
keydef[i].seg[j].flag= pos->key_part[j].key_part_flag;
170
if (options & HA_OPTION_PACK_KEYS ||
171
(pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY |
172
HA_SPACE_PACK_USED)))
174
if (pos->key_part[j].length > 8 &&
175
(type == HA_KEYTYPE_TEXT ||
176
type == HA_KEYTYPE_NUM ||
177
(type == HA_KEYTYPE_BINARY && !field->zero_pack())))
181
keydef[i].flag|= HA_PACK_KEY;
182
if (!(field->flags & ZEROFILL_FLAG) &&
183
(field->type() == MYSQL_TYPE_STRING ||
184
field->type() == MYSQL_TYPE_VAR_STRING ||
185
((int) (pos->key_part[j].length - field->decimals())) >= 4))
186
keydef[i].seg[j].flag|= HA_SPACE_PACK;
188
else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16))
189
keydef[i].flag|= HA_BINARY_PACK_KEY;
191
keydef[i].seg[j].type= (int) type;
192
keydef[i].seg[j].start= pos->key_part[j].offset;
193
keydef[i].seg[j].length= pos->key_part[j].length;
194
keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_end=
195
keydef[i].seg[j].bit_length= 0;
196
keydef[i].seg[j].bit_pos= 0;
197
keydef[i].seg[j].language= field->charset()->number;
201
keydef[i].seg[j].null_bit= field->null_bit;
202
keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
203
(uchar*) table_arg->record[0]);
207
keydef[i].seg[j].null_bit= 0;
208
keydef[i].seg[j].null_pos= 0;
210
if (field->type() == MYSQL_TYPE_BLOB ||
211
field->type() == MYSQL_TYPE_GEOMETRY)
213
keydef[i].seg[j].flag|= HA_BLOB_PART;
214
/* save number of bytes used to pack length */
215
keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
216
share->blob_ptr_size);
218
else if (field->type() == MYSQL_TYPE_BIT)
220
keydef[i].seg[j].bit_length= ((Field_bit *) field)->bit_len;
221
keydef[i].seg[j].bit_start= ((Field_bit *) field)->bit_ofs;
222
keydef[i].seg[j].bit_pos= (uint) (((Field_bit *) field)->bit_ptr -
223
(uchar*) table_arg->record[0]);
226
keyseg+= pos->key_parts;
228
if (table_arg->found_next_number_field)
229
keydef[share->next_number_index].flag|= HA_AUTO_KEY;
230
record= table_arg->record[0];
232
recinfo_pos= recinfo;
233
while (recpos < (uint) share->reclength)
235
Field **field, *found= 0;
236
minpos= share->reclength;
239
for (field= table_arg->field; *field; field++)
241
if ((fieldpos= (*field)->offset(record)) >= recpos &&
244
/* skip null fields */
245
if (!(temp_length= (*field)->pack_length_in_rec()))
246
continue; /* Skip null-fields */
247
if (! found || fieldpos < minpos ||
248
(fieldpos == minpos && temp_length < length))
256
DBUG_PRINT("loop", ("found: 0x%lx recpos: %d minpos: %d length: %d",
257
(long) found, recpos, minpos, length));
258
if (recpos != minpos)
259
{ // Reserved space (Null bits?)
260
bzero((char*) recinfo_pos, sizeof(*recinfo_pos));
261
recinfo_pos->type= (int) FIELD_NORMAL;
262
recinfo_pos++->length= (uint16) (minpos - recpos);
267
if (found->flags & BLOB_FLAG)
268
recinfo_pos->type= (int) FIELD_BLOB;
269
else if (found->type() == MYSQL_TYPE_VARCHAR)
270
recinfo_pos->type= FIELD_VARCHAR;
271
else if (!(options & HA_OPTION_PACK_RECORD))
272
recinfo_pos->type= (int) FIELD_NORMAL;
273
else if (found->zero_pack())
274
recinfo_pos->type= (int) FIELD_SKIP_ZERO;
276
recinfo_pos->type= (int) ((length <= 3 ||
277
(found->flags & ZEROFILL_FLAG)) ?
279
found->type() == MYSQL_TYPE_STRING ||
280
found->type() == MYSQL_TYPE_VAR_STRING ?
281
FIELD_SKIP_ENDSPACE :
282
FIELD_SKIP_PRESPACE);
285
recinfo_pos->null_bit= found->null_bit;
286
recinfo_pos->null_pos= (uint) (found->null_ptr -
287
(uchar*) table_arg->record[0]);
291
recinfo_pos->null_bit= 0;
292
recinfo_pos->null_pos= 0;
294
(recinfo_pos++)->length= (uint16) length;
295
recpos= minpos + length;
296
DBUG_PRINT("loop", ("length: %d type: %d",
297
recinfo_pos[-1].length,recinfo_pos[-1].type));
299
*records_out= (uint) (recinfo_pos - recinfo);
305
Check for underlying table conformance
309
t1_keyinfo in First table key definition
310
t1_recinfo in First table record definition
311
t1_keys in Number of keys in first table
312
t1_recs in Number of records in first table
313
t2_keyinfo in Second table key definition
314
t2_recinfo in Second table record definition
315
t2_keys in Number of keys in second table
316
t2_recs in Number of records in second table
317
strict in Strict check switch
320
This function compares two MyISAM definitions. By intention it was done
321
to compare merge table definition against underlying table definition.
322
It may also be used to compare dot-frm and MYI definitions of MyISAM
323
table as well to compare different MyISAM table definitions.
325
For merge table it is not required that number of keys in merge table
326
must exactly match number of keys in underlying table. When calling this
327
function for underlying table conformance check, 'strict' flag must be
328
set to false, and converted merge definition must be passed as t1_*.
330
Otherwise 'strict' flag must be set to 1 and it is not required to pass
331
converted dot-frm definition as t1_*.
334
0 - Equal definitions.
335
1 - Different definitions.
338
- compare FULLTEXT keys;
339
- compare SPATIAL keys;
340
- compare FIELD_SKIP_ZERO which is converted to FIELD_NORMAL correctly
341
(should be corretly detected in table2myisam).
344
int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
345
uint t1_keys, uint t1_recs,
346
MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
347
uint t2_keys, uint t2_recs, bool strict)
350
DBUG_ENTER("check_definition");
351
if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys))
353
DBUG_PRINT("error", ("Number of keys differs: t1_keys=%u, t2_keys=%u",
357
if (t1_recs != t2_recs)
359
DBUG_PRINT("error", ("Number of recs differs: t1_recs=%u, t2_recs=%u",
363
for (i= 0; i < t1_keys; i++)
365
HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg;
366
HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg;
367
if (t1_keyinfo[i].flag & HA_FULLTEXT && t2_keyinfo[i].flag & HA_FULLTEXT)
369
else if (t1_keyinfo[i].flag & HA_FULLTEXT ||
370
t2_keyinfo[i].flag & HA_FULLTEXT)
372
DBUG_PRINT("error", ("Key %d has different definition", i));
373
DBUG_PRINT("error", ("t1_fulltext= %d, t2_fulltext=%d",
374
test(t1_keyinfo[i].flag & HA_FULLTEXT),
375
test(t2_keyinfo[i].flag & HA_FULLTEXT)));
378
if (t1_keyinfo[i].flag & HA_SPATIAL && t2_keyinfo[i].flag & HA_SPATIAL)
380
else if (t1_keyinfo[i].flag & HA_SPATIAL ||
381
t2_keyinfo[i].flag & HA_SPATIAL)
383
DBUG_PRINT("error", ("Key %d has different definition", i));
384
DBUG_PRINT("error", ("t1_spatial= %d, t2_spatial=%d",
385
test(t1_keyinfo[i].flag & HA_SPATIAL),
386
test(t2_keyinfo[i].flag & HA_SPATIAL)));
389
if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs ||
390
t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg)
392
DBUG_PRINT("error", ("Key %d has different definition", i));
393
DBUG_PRINT("error", ("t1_keysegs=%d, t1_key_alg=%d",
394
t1_keyinfo[i].keysegs, t1_keyinfo[i].key_alg));
395
DBUG_PRINT("error", ("t2_keysegs=%d, t2_key_alg=%d",
396
t2_keyinfo[i].keysegs, t2_keyinfo[i].key_alg));
399
for (j= t1_keyinfo[i].keysegs; j--;)
401
uint8 t1_keysegs_j__type= t1_keysegs[j].type;
404
Table migration from 4.1 to 5.1. In 5.1 a *TEXT key part is
405
always HA_KEYTYPE_VARTEXT2. In 4.1 we had only the equivalent of
406
HA_KEYTYPE_VARTEXT1. Since we treat both the same on MyISAM
407
level, we can ignore a mismatch between these types.
409
if ((t1_keysegs[j].flag & HA_BLOB_PART) &&
410
(t2_keysegs[j].flag & HA_BLOB_PART))
412
if ((t1_keysegs_j__type == HA_KEYTYPE_VARTEXT2) &&
413
(t2_keysegs[j].type == HA_KEYTYPE_VARTEXT1))
414
t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1; /* purecov: tested */
415
else if ((t1_keysegs_j__type == HA_KEYTYPE_VARBINARY2) &&
416
(t2_keysegs[j].type == HA_KEYTYPE_VARBINARY1))
417
t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1; /* purecov: inspected */
420
if (t1_keysegs_j__type != t2_keysegs[j].type ||
421
t1_keysegs[j].language != t2_keysegs[j].language ||
422
t1_keysegs[j].null_bit != t2_keysegs[j].null_bit ||
423
t1_keysegs[j].length != t2_keysegs[j].length)
425
DBUG_PRINT("error", ("Key segment %d (key %d) has different "
426
"definition", j, i));
427
DBUG_PRINT("error", ("t1_type=%d, t1_language=%d, t1_null_bit=%d, "
429
t1_keysegs[j].type, t1_keysegs[j].language,
430
t1_keysegs[j].null_bit, t1_keysegs[j].length));
431
DBUG_PRINT("error", ("t2_type=%d, t2_language=%d, t2_null_bit=%d, "
433
t2_keysegs[j].type, t2_keysegs[j].language,
434
t2_keysegs[j].null_bit, t2_keysegs[j].length));
440
for (i= 0; i < t1_recs; i++)
442
MI_COLUMNDEF *t1_rec= &t1_recinfo[i];
443
MI_COLUMNDEF *t2_rec= &t2_recinfo[i];
445
FIELD_SKIP_ZERO can be changed to FIELD_NORMAL in mi_create,
446
see NOTE1 in mi_create.c
448
if ((t1_rec->type != t2_rec->type &&
449
!(t1_rec->type == (int) FIELD_SKIP_ZERO &&
450
t1_rec->length == 1 &&
451
t2_rec->type == (int) FIELD_NORMAL)) ||
452
t1_rec->length != t2_rec->length ||
453
t1_rec->null_bit != t2_rec->null_bit)
455
DBUG_PRINT("error", ("Field %d has different definition", i));
456
DBUG_PRINT("error", ("t1_type=%d, t1_length=%d, t1_null_bit=%d",
457
t1_rec->type, t1_rec->length, t1_rec->null_bit));
458
DBUG_PRINT("error", ("t2_type=%d, t2_length=%d, t2_null_bit=%d",
459
t2_rec->type, t2_rec->length, t2_rec->null_bit));
469
volatile int *killed_ptr(MI_CHECK *param)
471
/* In theory Unsafe conversion, but should be ok for now */
472
return (int*) &(((THD *)(param->thd))->killed);
475
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
477
param->error_printed|=1;
478
param->out_flag|= O_DATA_LOST;
481
mi_check_print_msg(param, "error", fmt, args);
485
void mi_check_print_info(MI_CHECK *param, const char *fmt,...)
489
mi_check_print_msg(param, "info", fmt, args);
493
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
495
param->warning_printed=1;
496
param->out_flag|= O_DATA_LOST;
499
mi_check_print_msg(param, "warning", fmt, args);
505
Report list of threads (and queries) accessing a table, thread_id of a
506
thread that detected corruption, ource file name and line number where
507
this corruption was detected, optional extra information (string).
509
This function is intended to be used when table corruption is detected.
511
@param[in] file MI_INFO object.
512
@param[in] message Optional error message.
513
@param[in] sfile Name of source file.
514
@param[in] sline Line number in source file.
519
void _mi_report_crashed(MI_INFO *file, const char *message,
520
const char *sfile, uint sline)
525
pthread_mutex_lock(&file->s->intern_lock);
526
if ((cur_thd= (THD*) file->in_use.data))
527
sql_print_error("Got an error from thread_id=%lu, %s:%d", cur_thd->thread_id,
530
sql_print_error("Got an error from unknown thread, %s:%d", sfile, sline);
532
sql_print_error("%s", message);
533
for (element= file->s->in_use; element; element= list_rest(element))
535
THD *thd= (THD*) element->data;
536
sql_print_error("%s", thd ? thd_security_context(thd, buf, sizeof(buf), 0)
537
: "Unknown thread accessing table");
539
pthread_mutex_unlock(&file->s->intern_lock);
545
ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
546
:handler(hton, table_arg), file(0),
547
int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
548
HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
549
HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
550
HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS |
551
HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS |
552
HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT |
553
HA_NEED_READ_RANGE_BUFFER | HA_MRR_CANT_SORT),
554
can_enable_indexes(1)
557
handler *ha_myisam::clone(MEM_ROOT *mem_root)
559
ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(mem_root));
561
new_handler->file->state= file->state;
566
static const char *ha_myisam_exts[] = {
572
const char **ha_myisam::bas_ext() const
574
return ha_myisam_exts;
578
const char *ha_myisam::index_type(uint key_number)
580
return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
582
(table->key_info[key_number].flags & HA_SPATIAL) ?
584
(table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
589
/* Name is here without an extension */
590
int ha_myisam::open(const char *name, int mode, uint test_if_locked)
593
MI_COLUMNDEF *recinfo= 0;
598
If the user wants to have memory mapped data files, add an
599
open_flag. Do not memory map temporary tables because they are
600
expected to be inserted and thus extended a lot. Memory mapping is
601
efficient for files that keep their size, but very inefficient for
602
growing files. Using an open_flag instead of calling mi_extra(...
603
HA_EXTRA_MMAP ...) after mi_open() has the advantage that the
604
mapping is not repeated for every open, but just done on the initial
605
open, when the MyISAM share is created. Everytime the server
606
requires to open a new instance of a table it calls this method. We
607
will always supply HA_OPEN_MMAP for a permanent table. However, the
608
MyISAM storage engine will ignore this flag if this is a secondary
609
open of a table that is in use by other threads already (if the
610
MyISAM share exists already).
612
if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
613
return (my_errno ? my_errno : -1);
614
if (!table->s->tmp_table) /* No need to perform a check for tmp table */
616
if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
618
/* purecov: begin inspected */
619
DBUG_PRINT("error", ("Failed to convert TABLE object to MyISAM "
620
"key and column definition"));
624
if (check_definition(keyinfo, recinfo, table->s->keys, recs,
625
file->s->keyinfo, file->s->rec,
626
file->s->base.keys, file->s->base.fields, true))
628
/* purecov: begin inspected */
629
my_errno= HA_ERR_CRASHED;
635
if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
636
VOID(mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0));
638
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
639
if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
640
VOID(mi_extra(file, HA_EXTRA_WAIT_LOCK, 0));
641
if (!table->s->db_record_offset)
642
int_table_flags|=HA_REC_NOT_IN_SEQ;
643
if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
644
int_table_flags|=HA_HAS_CHECKSUM;
646
keys_with_parts.clear_all();
647
for (i= 0; i < table->s->keys; i++)
649
table->key_info[i].block_size= file->s->keyinfo[i].block_length;
651
KEY_PART_INFO *kp= table->key_info[i].key_part;
652
KEY_PART_INFO *kp_end= kp + table->key_info[i].key_parts;
653
for (; kp != kp_end; kp++)
655
if (!kp->field->part_of_key.is_set(i))
657
keys_with_parts.set_bit(i);
668
Both recinfo and keydef are allocated by my_multi_malloc(), thus only
669
recinfo must be freed.
672
my_free((uchar*) recinfo, MYF(0));
676
int ha_myisam::close(void)
680
return mi_close(tmp);
683
int ha_myisam::write_row(uchar *buf)
685
ha_statistic_increment(&SSV::ha_write_count);
687
/* If we have a timestamp column, update it to the current time */
688
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
689
table->timestamp_field->set_time();
692
If we have an auto_increment column and we are writing a changed row
693
or a new row, then update the auto_increment value in the record.
695
if (table->next_number_field && buf == table->record[0])
698
if ((error= update_auto_increment()))
701
return mi_write(file,buf);
704
int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
706
if (!file) return HA_ADMIN_INTERNAL_ERROR;
709
MYISAM_SHARE* share = file->s;
710
const char *old_proc_info=thd->proc_info;
712
thd_proc_info(thd, "Checking table");
713
myisamchk_init(¶m);
715
param.op_name = "check";
716
param.db_name= table->s->db.str;
717
param.table_name= table->alias;
718
param.testflag = check_opt->flags | T_CHECK | T_SILENT;
719
param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
721
if (!(table->db_stat & HA_READ_ONLY))
722
param.testflag|= T_STATISTICS;
723
param.using_global_keycache = 1;
725
if (!mi_is_crashed(file) &&
726
(((param.testflag & T_CHECK_ONLY_CHANGED) &&
727
!(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
728
STATE_CRASHED_ON_REPAIR)) &&
729
share->state.open_count == 0) ||
730
((param.testflag & T_FAST) && (share->state.open_count ==
731
(uint) (share->global_changed ? 1 : 0)))))
732
return HA_ADMIN_ALREADY_DONE;
734
error = chk_status(¶m, file); // Not fatal
735
error = chk_size(¶m, file);
737
error |= chk_del(¶m, file, param.testflag);
739
error = chk_key(¶m, file);
742
if ((!(param.testflag & T_QUICK) &&
744
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
745
(param.testflag & (T_EXTEND | T_MEDIUM)))) ||
748
uint old_testflag=param.testflag;
749
param.testflag|=T_MEDIUM;
750
if (!(error= init_io_cache(¶m.read_cache, file->dfile,
751
my_default_record_cache_size, READ_CACHE,
752
share->pack.header_length, 1, MYF(MY_WME))))
754
error= chk_data_link(¶m, file, param.testflag & T_EXTEND);
755
end_io_cache(&(param.read_cache));
757
param.testflag= old_testflag;
762
if ((share->state.changed & (STATE_CHANGED |
763
STATE_CRASHED_ON_REPAIR |
764
STATE_CRASHED | STATE_NOT_ANALYZED)) ||
765
(param.testflag & T_STATISTICS) ||
768
file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
769
pthread_mutex_lock(&share->intern_lock);
770
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
771
STATE_CRASHED_ON_REPAIR);
772
if (!(table->db_stat & HA_READ_ONLY))
773
error=update_state_info(¶m,file,UPDATE_TIME | UPDATE_OPEN_COUNT |
775
pthread_mutex_unlock(&share->intern_lock);
776
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
780
else if (!mi_is_crashed(file) && !thd->killed)
782
mi_mark_crashed(file);
783
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
786
thd_proc_info(thd, old_proc_info);
787
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
792
analyze the key distribution in the table
793
As the table may be only locked for read, we have to take into account that
794
two threads may do an analyze at the same time!
797
int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
801
MYISAM_SHARE* share = file->s;
803
myisamchk_init(¶m);
805
param.op_name= "analyze";
806
param.db_name= table->s->db.str;
807
param.table_name= table->alias;
808
param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
809
T_DONT_CHECK_CHECKSUM);
810
param.using_global_keycache = 1;
811
param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
813
if (!(share->state.changed & STATE_NOT_ANALYZED))
814
return HA_ADMIN_ALREADY_DONE;
816
error = chk_key(¶m, file);
819
pthread_mutex_lock(&share->intern_lock);
820
error=update_state_info(¶m,file,UPDATE_STAT);
821
pthread_mutex_unlock(&share->intern_lock);
823
else if (!mi_is_crashed(file) && !thd->killed)
824
mi_mark_crashed(file);
825
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
829
int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
833
ha_rows start_records;
835
if (!file) return HA_ADMIN_INTERNAL_ERROR;
837
myisamchk_init(¶m);
839
param.op_name= "repair";
840
param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
841
T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
842
(check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
843
param.sort_buffer_length= check_opt->sort_buffer_size;
844
start_records=file->state->records;
845
while ((error=repair(thd,param,0)) && param.retry_repair)
847
param.retry_repair=0;
848
if (test_all_bits(param.testflag,
849
(uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
851
param.testflag&= ~T_RETRY_WITHOUT_QUICK;
852
sql_print_information("Retrying repair of: '%s' without quick",
856
param.testflag&= ~T_QUICK;
857
if ((param.testflag & T_REP_BY_SORT))
859
param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
860
sql_print_information("Retrying repair of: '%s' with keycache",
866
if (!error && start_records != file->state->records &&
867
!(check_opt->flags & T_VERY_SILENT))
869
char llbuff[22],llbuff2[22];
870
sql_print_information("Found %s of %s rows when repairing '%s'",
871
llstr(file->state->records, llbuff),
872
llstr(start_records, llbuff2),
878
int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
881
if (!file) return HA_ADMIN_INTERNAL_ERROR;
884
myisamchk_init(¶m);
886
param.op_name= "optimize";
887
param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
888
T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
889
param.sort_buffer_length= check_opt->sort_buffer_size;
890
if ((error= repair(thd,param,1)) && param.retry_repair)
892
sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying",
893
my_errno, param.db_name, param.table_name);
894
param.testflag&= ~T_REP_BY_SORT;
895
error= repair(thd,param,1);
901
int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_optimize)
904
uint local_testflag=param.testflag;
905
bool optimize_done= !do_optimize, statistics_done=0;
906
const char *old_proc_info=thd->proc_info;
907
char fixed_name[FN_REFLEN];
908
MYISAM_SHARE* share = file->s;
909
ha_rows rows= file->state->records;
910
DBUG_ENTER("ha_myisam::repair");
913
Normally this method is entered with a properly opened table. If the
914
repair fails, it can be repeated with more elaborate options. Under
915
special circumstances it can happen that a repair fails so that it
916
closed the data file and cannot re-open it. In this case file->dfile
917
is set to -1. We must not try another repair without an open data
920
if (file->dfile == -1)
922
sql_print_information("Retrying repair of: '%s' failed. "
923
"Please try REPAIR EXTENDED or myisamchk",
925
DBUG_RETURN(HA_ADMIN_FAILED);
928
param.db_name= table->s->db.str;
929
param.table_name= table->alias;
930
param.tmpfile_createflag = O_RDWR | O_TRUNC;
931
param.using_global_keycache = 1;
933
param.tmpdir= &mysql_tmpdir_list;
935
strmov(fixed_name,file->filename);
937
// Don't lock tables if we have used LOCK TABLE
938
if (!thd->locked_tables &&
939
mi_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK))
941
mi_check_print_error(¶m,ER(ER_CANT_LOCK),my_errno);
942
DBUG_RETURN(HA_ADMIN_FAILED);
946
((file->state->del || share->state.split != file->state->records) &&
947
(!(param.testflag & T_QUICK) ||
948
!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))))
950
uint64_t key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
951
mi_get_mask_all_keys_active(share->base.keys) :
952
share->state.key_map);
953
uint testflag=param.testflag;
954
if (mi_test_if_sort_rep(file,file->state->records,key_map,0) &&
955
(local_testflag & T_REP_BY_SORT))
957
local_testflag|= T_STATISTICS;
958
param.testflag|= T_STATISTICS; // We get this for free
960
if (thd->variables.myisam_repair_threads>1)
963
/* TODO: respect myisam_repair_threads variable */
964
my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
965
thd_proc_info(thd, buf);
966
error = mi_repair_parallel(¶m, file, fixed_name,
967
param.testflag & T_QUICK);
968
thd_proc_info(thd, "Repair done"); // to reset proc_info, as
969
// it was pointing to local buffer
973
thd_proc_info(thd, "Repair by sorting");
974
error = mi_repair_by_sort(¶m, file, fixed_name,
975
param.testflag & T_QUICK);
980
thd_proc_info(thd, "Repair with keycache");
981
param.testflag &= ~T_REP_BY_SORT;
982
error= mi_repair(¶m, file, fixed_name,
983
param.testflag & T_QUICK);
985
param.testflag=testflag;
990
if ((local_testflag & T_SORT_INDEX) &&
991
(share->state.changed & STATE_NOT_SORTED_PAGES))
994
thd_proc_info(thd, "Sorting index");
995
error=mi_sort_index(¶m,file,fixed_name);
997
if (!statistics_done && (local_testflag & T_STATISTICS))
999
if (share->state.changed & STATE_NOT_ANALYZED)
1002
thd_proc_info(thd, "Analyzing");
1003
error = chk_key(¶m, file);
1006
local_testflag&= ~T_STATISTICS; // Don't update statistics
1009
thd_proc_info(thd, "Saving state");
1012
if ((share->state.changed & STATE_CHANGED) || mi_is_crashed(file))
1014
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
1015
STATE_CRASHED_ON_REPAIR);
1016
file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1019
the following 'if', thought conceptually wrong,
1020
is a useful optimization nevertheless.
1022
if (file->state != &file->s->state.state)
1023
file->s->state.state = *file->state;
1024
if (file->s->base.auto_key)
1025
update_auto_increment_key(¶m, file, 1);
1027
error = update_state_info(¶m, file,
1028
UPDATE_TIME | UPDATE_OPEN_COUNT |
1030
T_STATISTICS ? UPDATE_STAT : 0));
1031
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
1033
if (rows != file->state->records && ! (param.testflag & T_VERY_SILENT))
1035
char llbuff[22],llbuff2[22];
1036
mi_check_print_warning(¶m,"Number of rows changed from %s to %s",
1038
llstr(file->state->records,llbuff2));
1043
mi_mark_crashed_on_repair(file);
1044
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
1045
update_state_info(¶m, file, 0);
1047
thd_proc_info(thd, old_proc_info);
1048
if (!thd->locked_tables)
1049
mi_lock_database(file,F_UNLCK);
1050
DBUG_RETURN(error ? HA_ADMIN_FAILED :
1051
!optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
1056
Assign table indexes to a specific key cache.
1059
int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
1061
KEY_CACHE *new_key_cache= check_opt->key_cache;
1062
const char *errmsg= 0;
1063
int error= HA_ADMIN_OK;
1065
TABLE_LIST *table_list= table->pos_in_table_list;
1066
DBUG_ENTER("ha_myisam::assign_to_keycache");
1068
table->keys_in_use_for_query.clear_all();
1070
if (table_list->process_index_hints(table))
1071
DBUG_RETURN(HA_ADMIN_FAILED);
1073
if (!table->keys_in_use_for_query.is_clear_all())
1074
/* use all keys if there's no list specified by the user through hints */
1075
map= table->keys_in_use_for_query.to_ulonglong();
1077
if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
1079
char buf[STRING_BUFFER_USUAL_SIZE];
1080
my_snprintf(buf, sizeof(buf),
1081
"Failed to flush to index file (errno: %d)", error);
1083
error= HA_ADMIN_CORRUPT;
1086
if (error != HA_ADMIN_OK)
1088
/* Send error to user */
1090
myisamchk_init(¶m);
1092
param.op_name= "assign_to_keycache";
1093
param.db_name= table->s->db.str;
1094
param.table_name= table->s->table_name.str;
1096
mi_check_print_error(¶m, errmsg);
1103
Preload pages of the index file for a table into the key cache.
1106
int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
1111
TABLE_LIST *table_list= table->pos_in_table_list;
1112
my_bool ignore_leaves= table_list->ignore_leaves;
1113
char buf[ERRMSGSIZE+20];
1115
DBUG_ENTER("ha_myisam::preload_keys");
1117
table->keys_in_use_for_query.clear_all();
1119
if (table_list->process_index_hints(table))
1120
DBUG_RETURN(HA_ADMIN_FAILED);
1123
/* Check validity of the index references */
1124
if (!table->keys_in_use_for_query.is_clear_all())
1125
/* use all keys if there's no list specified by the user through hints */
1126
map= table->keys_in_use_for_query.to_ulonglong();
1128
mi_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE,
1129
(void *) &thd->variables.preload_buff_size);
1131
if ((error= mi_preload(file, map, ignore_leaves)))
1134
case HA_ERR_NON_UNIQUE_BLOCK_SIZE:
1135
errmsg= "Indexes use different block sizes";
1137
case HA_ERR_OUT_OF_MEM:
1138
errmsg= "Failed to allocate buffer";
1141
my_snprintf(buf, ERRMSGSIZE,
1142
"Failed to read from index file (errno: %d)", my_errno);
1145
error= HA_ADMIN_FAILED;
1149
DBUG_RETURN(HA_ADMIN_OK);
1154
myisamchk_init(¶m);
1156
param.op_name= "preload_keys";
1157
param.db_name= table->s->db.str;
1158
param.table_name= table->s->table_name.str;
1160
mi_check_print_error(¶m, errmsg);
1167
Disable indexes, making it persistent if requested.
1171
mode mode of operation:
1172
HA_KEY_SWITCH_NONUNIQ disable all non-unique keys
1173
HA_KEY_SWITCH_ALL disable all keys
1174
HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
1175
HA_KEY_SWITCH_ALL_SAVE dis. all keys and make persistent
1178
HA_KEY_SWITCH_NONUNIQ is not implemented.
1179
HA_KEY_SWITCH_ALL_SAVE is not implemented.
1183
HA_ERR_WRONG_COMMAND mode not implemented.
1186
int ha_myisam::disable_indexes(uint mode)
1190
if (mode == HA_KEY_SWITCH_ALL)
1192
/* call a storage engine function to switch the key map */
1193
error= mi_disable_indexes(file);
1195
else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
1197
mi_extra(file, HA_EXTRA_NO_KEYS, 0);
1198
info(HA_STATUS_CONST); // Read new key info
1203
/* mode not implemented */
1204
error= HA_ERR_WRONG_COMMAND;
1211
Enable indexes, making it persistent if requested.
1215
mode mode of operation:
1216
HA_KEY_SWITCH_NONUNIQ enable all non-unique keys
1217
HA_KEY_SWITCH_ALL enable all keys
1218
HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
1219
HA_KEY_SWITCH_ALL_SAVE en. all keys and make persistent
1222
Enable indexes, which might have been disabled by disable_index() before.
1223
The modes without _SAVE work only if both data and indexes are empty,
1224
since the MyISAM repair would enable them persistently.
1225
To be sure in these cases, call handler::delete_all_rows() before.
1228
HA_KEY_SWITCH_NONUNIQ is not implemented.
1229
HA_KEY_SWITCH_ALL_SAVE is not implemented.
1233
!=0 Error, among others:
1234
HA_ERR_CRASHED data or index is non-empty. Delete all rows and retry.
1235
HA_ERR_WRONG_COMMAND mode not implemented.
1238
int ha_myisam::enable_indexes(uint mode)
1242
if (mi_is_all_keys_active(file->s->state.key_map, file->s->base.keys))
1244
/* All indexes are enabled already. */
1248
if (mode == HA_KEY_SWITCH_ALL)
1250
error= mi_enable_indexes(file);
1252
Do not try to repair on error,
1253
as this could make the enabled state persistent,
1254
but mode==HA_KEY_SWITCH_ALL forbids it.
1257
else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
1259
THD *thd=current_thd;
1261
const char *save_proc_info=thd->proc_info;
1262
thd_proc_info(thd, "Creating index");
1263
myisamchk_init(¶m);
1264
param.op_name= "recreating_index";
1265
param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
1266
T_CREATE_MISSING_KEYS);
1267
param.myf_rw&= ~MY_WAIT_IF_FULL;
1268
param.sort_buffer_length= thd->variables.myisam_sort_buff_size;
1269
param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
1270
param.tmpdir=&mysql_tmpdir_list;
1271
if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair)
1273
sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, retrying",
1274
my_errno, param.db_name, param.table_name);
1275
/* Repairing by sort failed. Now try standard repair method. */
1276
param.testflag&= ~(T_REP_BY_SORT | T_QUICK);
1277
error= (repair(thd,param,0) != HA_ADMIN_OK);
1279
If the standard repair succeeded, clear all error messages which
1280
might have been set by the first repair. They can still be seen
1281
with SHOW WARNINGS then.
1286
info(HA_STATUS_CONST);
1287
thd_proc_info(thd, save_proc_info);
1291
/* mode not implemented */
1292
error= HA_ERR_WRONG_COMMAND;
1299
Test if indexes are disabled.
1303
indexes_are_disabled()
1308
0 indexes are not disabled
1309
1 all indexes are disabled
1310
[2 non-unique indexes are disabled - NOT YET IMPLEMENTED]
1313
int ha_myisam::indexes_are_disabled(void)
1316
return mi_indexes_are_disabled(file);
1321
prepare for a many-rows insert operation
1322
e.g. - disable indexes (if they can be recreated fast) or
1323
activate special bulk-insert optimizations
1326
start_bulk_insert(rows)
1327
rows Rows to be inserted
1331
Do not forget to call end_bulk_insert() later!
1334
void ha_myisam::start_bulk_insert(ha_rows rows)
1336
DBUG_ENTER("ha_myisam::start_bulk_insert");
1337
THD *thd= current_thd;
1338
ulong size= min(thd->variables.read_buff_size,
1339
(ulong) (table->s->avg_row_length*rows));
1340
DBUG_PRINT("info",("start_bulk_insert: rows %lu size %lu",
1341
(ulong) rows, size));
1343
/* don't enable row cache if too few rows */
1344
if (! rows || (rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE))
1345
mi_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &size);
1347
can_enable_indexes= mi_is_all_keys_active(file->s->state.key_map,
1348
file->s->base.keys);
1350
if (!(specialflag & SPECIAL_SAFE_MODE))
1353
Only disable old index if the table was empty and we are inserting
1355
We should not do this for only a few rows as this is slower and
1356
we don't want to update the key statistics based of only a few rows.
1358
if (file->state->records == 0 && can_enable_indexes &&
1359
(!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES))
1360
mi_disable_non_unique_index(file,rows);
1362
if (!file->bulk_insert &&
1363
(!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT))
1365
mi_init_bulk_insert(file, thd->variables.bulk_insert_buff_size, rows);
1372
end special bulk-insert optimizations,
1373
which have been activated by start_bulk_insert().
1384
int ha_myisam::end_bulk_insert()
1386
mi_end_bulk_insert(file);
1387
int err=mi_extra(file, HA_EXTRA_NO_CACHE, 0);
1388
return err ? err : can_enable_indexes ?
1389
enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE) : 0;
1393
bool ha_myisam::check_and_repair(THD *thd)
1398
uint old_query_length;
1399
HA_CHECK_OPT check_opt;
1400
DBUG_ENTER("ha_myisam::check_and_repair");
1403
check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
1404
// Don't use quick if deleted rows
1405
if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
1406
check_opt.flags|=T_QUICK;
1407
sql_print_warning("Checking table: '%s'",table->s->path.str);
1409
old_query= thd->query;
1410
old_query_length= thd->query_length;
1411
pthread_mutex_lock(&LOCK_thread_count);
1412
thd->query= table->s->table_name.str;
1413
thd->query_length= table->s->table_name.length;
1414
pthread_mutex_unlock(&LOCK_thread_count);
1416
if ((marked_crashed= mi_is_crashed(file)) || check(thd, &check_opt))
1418
sql_print_warning("Recovering table: '%s'",table->s->path.str);
1420
((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
1421
(marked_crashed ? 0 : T_QUICK) |
1422
(myisam_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
1424
if (repair(thd, &check_opt))
1427
pthread_mutex_lock(&LOCK_thread_count);
1428
thd->query= old_query;
1429
thd->query_length= old_query_length;
1430
pthread_mutex_unlock(&LOCK_thread_count);
1434
bool ha_myisam::is_crashed() const
1436
return (file->s->state.changed & STATE_CRASHED ||
1437
(my_disable_locking && file->s->state.open_count));
1440
int ha_myisam::update_row(const uchar *old_data, uchar *new_data)
1442
ha_statistic_increment(&SSV::ha_update_count);
1443
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
1444
table->timestamp_field->set_time();
1445
return mi_update(file,old_data,new_data);
1448
int ha_myisam::delete_row(const uchar *buf)
1450
ha_statistic_increment(&SSV::ha_delete_count);
1451
return mi_delete(file,buf);
1456
my_bool index_cond_func_myisam(void *arg)
1458
ha_myisam *h= (ha_myisam*)arg;
1459
/*if (h->in_range_read)*/
1462
if (h->compare_key2(h->end_range) > 0)
1463
return 2; /* caller should return HA_ERR_END_OF_FILE already */
1465
return (my_bool)h->pushed_idx_cond->val_int();
1471
int ha_myisam::index_init(uint idx, bool sorted)
1474
//in_range_read= FALSE;
1475
if (pushed_idx_cond_keyno == idx)
1476
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1481
int ha_myisam::index_end()
1483
active_index=MAX_KEY;
1484
//pushed_idx_cond_keyno= MAX_KEY;
1485
mi_set_index_cond_func(file, NULL, 0);
1486
in_range_check_pushed_down= FALSE;
1487
ds_mrr.dsmrr_close();
1492
int ha_myisam::index_read_map(uchar *buf, const uchar *key,
1493
key_part_map keypart_map,
1494
enum ha_rkey_function find_flag)
1496
DBUG_ASSERT(inited==INDEX);
1497
ha_statistic_increment(&SSV::ha_read_key_count);
1498
int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
1499
table->status=error ? STATUS_NOT_FOUND: 0;
1503
int ha_myisam::index_read_idx_map(uchar *buf, uint index, const uchar *key,
1504
key_part_map keypart_map,
1505
enum ha_rkey_function find_flag)
1507
ha_statistic_increment(&SSV::ha_read_key_count);
1508
int error=mi_rkey(file, buf, index, key, keypart_map, find_flag);
1509
table->status=error ? STATUS_NOT_FOUND: 0;
1513
int ha_myisam::index_read_last_map(uchar *buf, const uchar *key,
1514
key_part_map keypart_map)
1516
DBUG_ENTER("ha_myisam::index_read_last");
1517
DBUG_ASSERT(inited==INDEX);
1518
ha_statistic_increment(&SSV::ha_read_key_count);
1519
int error=mi_rkey(file, buf, active_index, key, keypart_map,
1520
HA_READ_PREFIX_LAST);
1521
table->status=error ? STATUS_NOT_FOUND: 0;
1525
int ha_myisam::index_next(uchar *buf)
1527
DBUG_ASSERT(inited==INDEX);
1528
ha_statistic_increment(&SSV::ha_read_next_count);
1529
int error=mi_rnext(file,buf,active_index);
1530
table->status=error ? STATUS_NOT_FOUND: 0;
1534
int ha_myisam::index_prev(uchar *buf)
1536
DBUG_ASSERT(inited==INDEX);
1537
ha_statistic_increment(&SSV::ha_read_prev_count);
1538
int error=mi_rprev(file,buf, active_index);
1539
table->status=error ? STATUS_NOT_FOUND: 0;
1543
int ha_myisam::index_first(uchar *buf)
1545
DBUG_ASSERT(inited==INDEX);
1546
ha_statistic_increment(&SSV::ha_read_first_count);
1547
int error=mi_rfirst(file, buf, active_index);
1548
table->status=error ? STATUS_NOT_FOUND: 0;
1552
int ha_myisam::index_last(uchar *buf)
1554
DBUG_ASSERT(inited==INDEX);
1555
ha_statistic_increment(&SSV::ha_read_last_count);
1556
int error=mi_rlast(file, buf, active_index);
1557
table->status=error ? STATUS_NOT_FOUND: 0;
1561
int ha_myisam::index_next_same(uchar *buf,
1562
const uchar *key __attribute__((unused)),
1563
uint length __attribute__((unused)))
1566
DBUG_ASSERT(inited==INDEX);
1567
ha_statistic_increment(&SSV::ha_read_next_count);
1570
error= mi_rnext_same(file,buf);
1571
} while (error == HA_ERR_RECORD_DELETED);
1572
table->status=error ? STATUS_NOT_FOUND: 0;
1576
int ha_myisam::read_range_first(const key_range *start_key,
1577
const key_range *end_key,
1579
bool sorted /* ignored */)
1582
//if (!eq_range_arg)
1583
// in_range_read= TRUE;
1585
res= handler::read_range_first(start_key, end_key, eq_range_arg, sorted);
1588
// in_range_read= FALSE;
1593
int ha_myisam::read_range_next()
1595
int res= handler::read_range_next();
1597
// in_range_read= FALSE;
1602
int ha_myisam::rnd_init(bool scan)
1605
return mi_scan_init(file);
1606
return mi_reset(file); // Free buffers
1609
int ha_myisam::rnd_next(uchar *buf)
1611
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1612
int error=mi_scan(file, buf);
1613
table->status=error ? STATUS_NOT_FOUND: 0;
1617
int ha_myisam::restart_rnd_next(uchar *buf, uchar *pos)
1619
return rnd_pos(buf,pos);
1622
int ha_myisam::rnd_pos(uchar *buf, uchar *pos)
1624
ha_statistic_increment(&SSV::ha_read_rnd_count);
1625
int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
1626
table->status=error ? STATUS_NOT_FOUND: 0;
1631
void ha_myisam::position(const uchar *record)
1633
my_off_t row_position= mi_position(file);
1634
my_store_ptr(ref, ref_length, row_position);
1637
int ha_myisam::info(uint flag)
1639
MI_ISAMINFO misam_info;
1640
char name_buff[FN_REFLEN];
1642
(void) mi_status(file,&misam_info,flag);
1643
if (flag & HA_STATUS_VARIABLE)
1645
stats.records= misam_info.records;
1646
stats.deleted= misam_info.deleted;
1647
stats.data_file_length= misam_info.data_file_length;
1648
stats.index_file_length= misam_info.index_file_length;
1649
stats.delete_length= misam_info.delete_length;
1650
stats.check_time= misam_info.check_time;
1651
stats.mean_rec_length= misam_info.mean_reclength;
1653
if (flag & HA_STATUS_CONST)
1655
TABLE_SHARE *share= table->s;
1656
stats.max_data_file_length= misam_info.max_data_file_length;
1657
stats.max_index_file_length= misam_info.max_index_file_length;
1658
stats.create_time= misam_info.create_time;
1659
ref_length= misam_info.reflength;
1660
share->db_options_in_use= misam_info.options;
1661
stats.block_size= myisam_block_size; /* record block size */
1664
if (share->tmp_table == NO_TMP_TABLE)
1665
pthread_mutex_lock(&share->mutex);
1666
share->keys_in_use.set_prefix(share->keys);
1667
share->keys_in_use.intersect_extended(misam_info.key_map);
1668
share->keys_for_keyread.intersect(share->keys_in_use);
1669
share->db_record_offset= misam_info.record_offset;
1670
if (share->key_parts)
1671
memcpy((char*) table->key_info[0].rec_per_key,
1672
(char*) misam_info.rec_per_key,
1673
sizeof(table->key_info[0].rec_per_key)*share->key_parts);
1674
if (share->tmp_table == NO_TMP_TABLE)
1675
pthread_mutex_unlock(&share->mutex);
1678
Set data_file_name and index_file_name to point at the symlink value
1679
if table is symlinked (Ie; Real name is not same as generated name)
1681
data_file_name= index_file_name= 0;
1682
fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1683
MY_APPEND_EXT | MY_UNPACK_FILENAME);
1684
if (strcmp(name_buff, misam_info.data_file_name))
1685
data_file_name=misam_info.data_file_name;
1686
fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1687
MY_APPEND_EXT | MY_UNPACK_FILENAME);
1688
if (strcmp(name_buff, misam_info.index_file_name))
1689
index_file_name=misam_info.index_file_name;
1691
if (flag & HA_STATUS_ERRKEY)
1693
errkey = misam_info.errkey;
1694
my_store_ptr(dup_ref, ref_length, misam_info.dupp_key_pos);
1696
if (flag & HA_STATUS_TIME)
1697
stats.update_time = misam_info.update_time;
1698
if (flag & HA_STATUS_AUTO)
1699
stats.auto_increment_value= misam_info.auto_increment;
1705
int ha_myisam::extra(enum ha_extra_function operation)
1707
if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_KEYREAD)
1709
return mi_extra(file, operation, 0);
1712
int ha_myisam::reset(void)
1714
pushed_idx_cond= NULL;
1715
pushed_idx_cond_keyno= MAX_KEY;
1716
mi_set_index_cond_func(file, NULL, 0);
1717
ds_mrr.dsmrr_close();
1718
return mi_reset(file);
1721
/* To be used with WRITE_CACHE and EXTRA_CACHE */
1723
int ha_myisam::extra_opt(enum ha_extra_function operation, ulong cache_size)
1725
if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE)
1727
return mi_extra(file, operation, (void*) &cache_size);
1730
int ha_myisam::delete_all_rows()
1732
return mi_delete_all_rows(file);
1735
int ha_myisam::delete_table(const char *name)
1737
return mi_delete_table(name);
1741
int ha_myisam::external_lock(THD *thd, int lock_type)
1743
file->in_use.data= thd;
1744
return mi_lock_database(file, !table->s->tmp_table ?
1745
lock_type : ((lock_type == F_UNLCK) ?
1746
F_UNLCK : F_EXTRA_LCK));
1749
THR_LOCK_DATA **ha_myisam::store_lock(THD *thd,
1751
enum thr_lock_type lock_type)
1753
if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
1754
file->lock.type=lock_type;
1759
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
1761
ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
1762
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
1764
create_info->auto_increment_value= stats.auto_increment_value;
1766
create_info->data_file_name=data_file_name;
1767
create_info->index_file_name=index_file_name;
1771
int ha_myisam::create(const char *name, register TABLE *table_arg,
1772
HA_CREATE_INFO *ha_create_info)
1775
uint create_flags= 0, records, i;
1776
char buff[FN_REFLEN];
1778
MI_COLUMNDEF *recinfo;
1779
MI_CREATE_INFO create_info;
1780
TABLE_SHARE *share= table_arg->s;
1781
uint options= share->db_options_in_use;
1782
DBUG_ENTER("ha_myisam::create");
1783
for (i= 0; i < share->keys; i++)
1785
if (table_arg->key_info[i].flags & HA_USES_PARSER)
1787
create_flags|= HA_CREATE_RELIES_ON_SQL_LAYER;
1791
if ((error= table2myisam(table_arg, &keydef, &recinfo, &records)))
1792
DBUG_RETURN(error); /* purecov: inspected */
1793
bzero((char*) &create_info, sizeof(create_info));
1794
create_info.max_rows= share->max_rows;
1795
create_info.reloc_rows= share->min_rows;
1796
create_info.with_auto_increment= share->next_number_key_offset == 0;
1797
create_info.auto_increment= (ha_create_info->auto_increment_value ?
1798
ha_create_info->auto_increment_value -1 :
1800
create_info.data_file_length= ((uint64_t) share->max_rows *
1801
share->avg_row_length);
1802
create_info.data_file_name= ha_create_info->data_file_name;
1803
create_info.index_file_name= ha_create_info->index_file_name;
1804
create_info.language= share->table_charset->number;
1806
if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
1807
create_flags|= HA_CREATE_TMP_TABLE;
1808
if (ha_create_info->options & HA_CREATE_KEEP_FILES)
1809
create_flags|= HA_CREATE_KEEP_FILES;
1810
if (options & HA_OPTION_PACK_RECORD)
1811
create_flags|= HA_PACK_RECORD;
1812
if (options & HA_OPTION_CHECKSUM)
1813
create_flags|= HA_CREATE_CHECKSUM;
1814
if (options & HA_OPTION_DELAY_KEY_WRITE)
1815
create_flags|= HA_CREATE_DELAY_KEY_WRITE;
1817
/* TODO: Check that the following fn_format is really needed */
1818
error= mi_create(fn_format(buff, name, "", "",
1819
MY_UNPACK_FILENAME|MY_APPEND_EXT),
1820
share->keys, keydef,
1822
0, (MI_UNIQUEDEF*) 0,
1823
&create_info, create_flags);
1824
my_free((uchar*) recinfo, MYF(0));
1829
int ha_myisam::rename_table(const char * from, const char * to)
1831
return mi_rename(from,to);
1835
void ha_myisam::get_auto_increment(uint64_t offset, uint64_t increment,
1836
uint64_t nb_desired_values,
1837
uint64_t *first_value,
1838
uint64_t *nb_reserved_values)
1842
uchar key[MI_MAX_KEY_LENGTH];
1844
if (!table->s->next_number_key_offset)
1845
{ // Autoincrement at key-start
1846
ha_myisam::info(HA_STATUS_AUTO);
1847
*first_value= stats.auto_increment_value;
1848
/* MyISAM has only table-level lock, so reserves to +inf */
1849
*nb_reserved_values= ULONGLONG_MAX;
1853
/* it's safe to call the following if bulk_insert isn't on */
1854
mi_flush_bulk_insert(file, table->s->next_number_index);
1856
(void) extra(HA_EXTRA_KEYREAD);
1857
key_copy(key, table->record[0],
1858
table->key_info + table->s->next_number_index,
1859
table->s->next_number_key_offset);
1860
error= mi_rkey(file, table->record[1], (int) table->s->next_number_index,
1861
key, make_prev_keypart_map(table->s->next_number_keypart),
1862
HA_READ_PREFIX_LAST);
1867
/* Get data from record[1] */
1868
nr= ((uint64_t) table->next_number_field->
1869
val_int_offset(table->s->rec_buff_length)+1);
1871
extra(HA_EXTRA_NO_KEYREAD);
1874
MySQL needs to call us for next row: assume we are inserting ("a",null)
1875
here, we return 3, and next this statement will want to insert ("b",null):
1876
there is no reason why ("b",3+1) would be the good row to insert: maybe it
1877
already exists, maybe 3+1 is too large...
1879
*nb_reserved_values= 1;
1884
Find out how many rows there is in the given range
1889
min_key Start of range. Null pointer if from first key
1890
max_key End of range. Null pointer if to last key
1893
min_key.flag can have one of the following values:
1894
HA_READ_KEY_EXACT Include the key in the range
1895
HA_READ_AFTER_KEY Don't include key in range
1897
max_key.flag can have one of the following values:
1898
HA_READ_BEFORE_KEY Don't include key in range
1899
HA_READ_AFTER_KEY Include all 'end_key' values in the range
1902
HA_POS_ERROR Something is wrong with the index tree.
1903
0 There is no matching keys in the given range
1904
number > 0 There is approximately 'number' matching rows in
1908
ha_rows ha_myisam::records_in_range(uint inx, key_range *min_key,
1911
return (ha_rows) mi_records_in_range(file, (int) inx, min_key, max_key);
1915
int ha_myisam::ft_read(uchar *buf)
1922
thread_safe_increment(table->in_use->status_var.ha_read_next_count,
1923
&LOCK_status); // why ?
1925
error=ft_handler->please->read_next(ft_handler,(char*) buf);
1927
table->status=error ? STATUS_NOT_FOUND: 0;
1931
uint ha_myisam::checksum() const
1933
return (uint)file->state->checksum;
1937
bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
1940
uint options= table->s->db_options_in_use;
1942
if (info->auto_increment_value != stats.auto_increment_value ||
1943
info->data_file_name != data_file_name ||
1944
info->index_file_name != index_file_name ||
1945
table_changes == IS_EQUAL_NO ||
1946
table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
1947
return COMPATIBLE_DATA_NO;
1949
if ((options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1950
HA_OPTION_DELAY_KEY_WRITE)) !=
1951
(info->table_options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1952
HA_OPTION_DELAY_KEY_WRITE)))
1953
return COMPATIBLE_DATA_NO;
1954
return COMPATIBLE_DATA_YES;
1957
extern int mi_panic(enum ha_panic_function flag);
1958
int myisam_panic(handlerton *hton, ha_panic_function flag)
1960
return mi_panic(flag);
1963
static int myisam_init(void *p)
1965
handlerton *myisam_hton;
1967
myisam_hton= (handlerton *)p;
1968
myisam_hton->state= SHOW_OPTION_YES;
1969
myisam_hton->db_type= DB_TYPE_MYISAM;
1970
myisam_hton->create= myisam_create_handler;
1971
myisam_hton->panic= myisam_panic;
1972
myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
1978
/****************************************************************************
1979
* MyISAM MRR implementation: use DS-MRR
1980
***************************************************************************/
1982
int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
1983
uint n_ranges, uint mode,
1984
HANDLER_BUFFER *buf)
1986
return ds_mrr.dsmrr_init(this, &table->key_info[active_index],
1987
seq, seq_init_param, n_ranges, mode, buf);
1990
int ha_myisam::multi_range_read_next(char **range_info)
1992
return ds_mrr.dsmrr_next(this, range_info);
1995
ha_rows ha_myisam::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
1996
void *seq_init_param,
1997
uint n_ranges, uint *bufsz,
1998
uint *flags, COST_VECT *cost)
2001
This call is here because there is no location where this->table would
2003
TODO: consider moving it into some per-query initialization call.
2005
ds_mrr.init(this, table);
2006
return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz,
2010
int ha_myisam::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
2011
uint *bufsz, uint *flags, COST_VECT *cost)
2013
ds_mrr.init(this, table);
2014
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
2017
/* MyISAM MRR implementation ends */
2020
/* Index condition pushdown implementation*/
2023
Item *ha_myisam::idx_cond_push(uint keyno_arg, Item* idx_cond_arg)
2025
pushed_idx_cond_keyno= keyno_arg;
2026
pushed_idx_cond= idx_cond_arg;
2027
in_range_check_pushed_down= TRUE;
2028
if (active_index == pushed_idx_cond_keyno)
2029
mi_set_index_cond_func(file, index_cond_func_myisam, this);
2034
struct st_mysql_storage_engine myisam_storage_engine=
2035
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
2037
mysql_declare_plugin(myisam)
2039
MYSQL_STORAGE_ENGINE_PLUGIN,
2040
&myisam_storage_engine,
2043
"Default engine as of MySQL 3.23 with great performance",
2045
myisam_init, /* Plugin Init */
2046
NULL, /* Plugin Deinit */
2048
NULL, /* status variables */
2049
NULL, /* system variables */
2050
NULL /* config options */
2052
mysql_declare_plugin_end;
2055
#ifdef HAVE_QUERY_CACHE
2057
@brief Register a named table with a call back function to the query cache.
2059
@param thd The thread handle
2060
@param table_key A pointer to the table name in the table cache
2061
@param key_length The length of the table name
2062
@param[out] engine_callback The pointer to the storage engine call back
2063
function, currently 0
2064
@param[out] engine_data Engine data will be set to 0.
2066
@note Despite the name of this function, it is used to check each statement
2067
before it is cached and not to register a table or callback function.
2069
@see handler::register_query_cache_table
2071
@return The error code. The engine_data and engine_callback will be set to 0.
2072
@retval TRUE Success
2073
@retval FALSE An error occured
2076
my_bool ha_myisam::register_query_cache_table(THD *thd, char *table_name,
2077
uint table_name_len,
2080
uint64_t *engine_data)
2082
DBUG_ENTER("ha_myisam::register_query_cache_table");
2084
No call back function is needed to determine if a cached statement
2087
*engine_callback= 0;
2090
No engine data is needed.
2094
if (file->s->concurrent_insert)
2097
If a concurrent INSERT has happened just before the currently
2098
processed SELECT statement, the total size of the table is
2101
To determine if the table size is known, the current thread's snap
2102
shot of the table size with the actual table size are compared.
2104
If the table size is unknown the SELECT statement can't be cached.
2106
When concurrent inserts are disabled at table open, mi_open()
2107
does not assign a get_status() function. In this case the local
2108
("current") status is never updated. We would wrongly think that
2109
we cannot cache the statement.
2111
uint64_t actual_data_file_length;
2112
uint64_t current_data_file_length;
2115
POSIX visibility rules specify that "2. Whatever memory values a
2116
thread can see when it unlocks a mutex <...> can also be seen by any
2117
thread that later locks the same mutex". In this particular case,
2118
concurrent insert thread had modified the data_file_length in
2119
MYISAM_SHARE before it has unlocked (or even locked)
2120
structure_guard_mutex. So, here we're guaranteed to see at least that
2121
value after we've locked the same mutex. We can see a later value
2122
(modified by some other thread) though, but it's ok, as we only want
2123
to know if the variable was changed, the actual new value doesn't matter
2125
actual_data_file_length= file->s->state.state.data_file_length;
2126
current_data_file_length= file->save_state.data_file_length;
2128
if (current_data_file_length != actual_data_file_length)
2130
/* Don't cache current statement. */
2135
/* It is ok to try to cache current statement. */