12
12
You should have received a copy of the GNU General Public License
13
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
19
#include "drizzled/internal/my_bit.h"
20
#include "myisampack.h"
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>
21
27
#include "ha_myisam.h"
22
#include "myisam_priv.h"
23
#include "drizzled/option.h"
24
#include "drizzled/internal/my_bit.h"
25
#include "drizzled/internal/m_string.h"
26
#include "drizzled/util/test.h"
27
#include "drizzled/error.h"
28
#include "drizzled/errmsg_print.h"
29
#include "drizzled/gettext.h"
30
#include "drizzled/session.h"
31
#include "drizzled/plugin.h"
32
#include "drizzled/plugin/client.h"
33
#include "drizzled/table.h"
34
#include "drizzled/field/timestamp.h"
35
#include "drizzled/memory/multi_malloc.h"
36
#include "drizzled/plugin/daemon.h"
38
#include <boost/algorithm/string.hpp>
39
#include <boost/scoped_ptr.hpp>
46
#include <boost/program_options.hpp>
47
#include <drizzled/module/option_map.h>
49
namespace po= boost::program_options;
52
using namespace drizzled;
54
static const string engine_name("MyISAM");
56
boost::mutex THR_LOCK_myisam;
58
static uint32_t myisam_key_cache_block_size= KEY_CACHE_BLOCK_SIZE;
59
static uint32_t myisam_key_cache_size;
60
static uint32_t myisam_key_cache_division_limit;
61
static uint32_t myisam_key_cache_age_threshold;
62
static uint64_t max_sort_file_size;
63
typedef constrained_check<size_t, SIZE_MAX, 1024, 1024> sort_buffer_constraint;
64
static sort_buffer_constraint sort_buffer_size;
66
void st_mi_isam_share::setKeyCache()
68
(void)init_key_cache(&key_cache,
69
myisam_key_cache_block_size,
70
myisam_key_cache_size,
71
myisam_key_cache_division_limit,
72
myisam_key_cache_age_threshold);
29
#include "myisamdef.h"
31
ulong myisam_recover_options= HA_RECOVER_NONE;
33
/* bits in myisam_recover_options */
34
const char *myisam_recover_names[] =
35
{ "DEFAULT", "BACKUP", "FORCE", "QUICK", NullS};
36
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
37
myisam_recover_names, NULL};
39
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
40
"nulls_ignored", NullS};
41
TYPELIB myisam_stats_method_typelib= {
42
array_elements(myisam_stats_method_names) - 1, "",
43
myisam_stats_method_names, NULL};
75
46
/*****************************************************************************
77
48
*****************************************************************************/
79
static const char *ha_myisam_exts[] = {
85
class MyisamEngine : public plugin::StorageEngine
88
MyisamEngine(const MyisamEngine&);
89
MyisamEngine& operator=(const MyisamEngine&);
91
explicit MyisamEngine(string name_arg) :
92
plugin::StorageEngine(name_arg,
93
HTON_CAN_INDEX_BLOBS |
94
HTON_STATS_RECORDS_IS_EXACT |
100
HTON_SKIP_STORE_LOCK)
104
virtual ~MyisamEngine()
106
mi_panic(HA_PANIC_CLOSE);
109
virtual Cursor *create(Table &table)
111
return new ha_myisam(*this, table);
114
const char **bas_ext() const {
115
return ha_myisam_exts;
118
int doCreateTable(Session&,
120
const TableIdentifier &identifier,
123
int doRenameTable(Session&, const TableIdentifier &from, const TableIdentifier &to);
125
int doDropTable(Session&, const TableIdentifier &identifier);
127
int doGetTableDefinition(Session& session,
128
const TableIdentifier &identifier,
129
message::Table &table_message);
131
uint32_t max_supported_keys() const { return MI_MAX_KEY; }
132
uint32_t max_supported_key_length() const { return MI_MAX_KEY_LENGTH; }
133
uint32_t max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
135
uint32_t index_flags(enum ha_key_alg) const
137
return (HA_READ_NEXT |
143
bool doDoesTableExist(Session& session, const TableIdentifier &identifier);
145
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
146
const drizzled::SchemaIdentifier &schema_identifier,
147
drizzled::TableIdentifier::vector &set_of_identifiers);
148
bool validateCreateTableOption(const std::string &key, const std::string &state)
151
if (boost::iequals(key, "ROW_FORMAT"))
160
void MyisamEngine::doGetTableIdentifiers(drizzled::CachedDirectory&,
161
const drizzled::SchemaIdentifier&,
162
drizzled::TableIdentifier::vector&)
166
bool MyisamEngine::doDoesTableExist(Session &session, const TableIdentifier &identifier)
168
return session.getMessageCache().doesTableMessageExist(identifier);
171
int MyisamEngine::doGetTableDefinition(Session &session,
172
const TableIdentifier &identifier,
173
message::Table &table_message)
175
if (session.getMessageCache().getTableMessage(identifier, table_message))
181
Convert to push_Warnings if you ever care about this, otherwise, it is a no-op.
184
static void mi_check_print_msg(MI_CHECK *, const char* ,
185
const char *, va_list )
50
static handler *myisam_create_handler(handlerton *hton,
54
return new (mem_root) ha_myisam(hton, table);
57
// collect errors printed by mi_check routines
59
static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
60
const char *fmt, va_list args)
62
THD* thd = (THD*)param->thd;
63
Protocol *protocol= thd->protocol;
64
uint length, msg_length;
65
char msgbuf[MI_MAX_MSG_BUF];
66
char name[NAME_LEN*2+2];
68
msg_length= vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
69
msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
71
DBUG_PRINT(msg_type,("message: %s",msgbuf));
75
sql_print_error(msgbuf);
79
if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
82
my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
85
length=(uint) (strxmov(name, param->db_name,".",param->table_name,NullS) -
88
TODO: switch from protocol to push_warning here. The main reason we didn't
89
it yet is parallel repair. Due to following trace:
90
mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
92
Also we likely need to lock mutex here (in both cases with protocol and
95
protocol->prepare_for_resend();
96
protocol->store(name, length, system_charset_info);
97
protocol->store(param->op_name, system_charset_info);
98
protocol->store(msg_type, system_charset_info);
99
protocol->store(msgbuf, msg_length, system_charset_info);
100
if (protocol->write())
101
sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
191
Convert Table object to MyISAM key and column definition
108
Convert TABLE object to MyISAM key and column definition
195
table_arg in Table object.
112
table_arg in TABLE object.
196
113
keydef_out out MyISAM key definition.
197
114
recinfo_out out MyISAM column definition.
198
115
records_out out Number of fields.
214
static int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
215
MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
131
int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
132
MI_COLUMNDEF **recinfo_out, uint *records_out)
217
uint32_t i, j, recpos, minpos, fieldpos, temp_length, length;
134
uint i, j, recpos, minpos, fieldpos, temp_length, length;
218
135
enum ha_base_keytype type= HA_KEYTYPE_BINARY;
219
unsigned char *record;
220
138
MI_KEYDEF *keydef;
221
139
MI_COLUMNDEF *recinfo, *recinfo_pos;
222
140
HA_KEYSEG *keyseg;
223
TableShare *share= table_arg->getMutableShare();
224
uint32_t options= share->db_options_in_use;
225
if (!(memory::multi_malloc(false,
226
recinfo_out, (share->sizeFields() * 2 + 2) * sizeof(MI_COLUMNDEF),
227
keydef_out, share->sizeKeys() * sizeof(MI_KEYDEF),
228
&keyseg, (share->key_parts + share->sizeKeys()) * sizeof(HA_KEYSEG),
230
return(HA_ERR_OUT_OF_MEM);
141
TABLE_SHARE *share= table_arg->s;
142
uint options= share->db_options_in_use;
143
DBUG_ENTER("table2myisam");
144
if (!(my_multi_malloc(MYF(MY_WME),
145
recinfo_out, (share->fields * 2 + 2) * sizeof(MI_COLUMNDEF),
146
keydef_out, share->keys * sizeof(MI_KEYDEF),
148
(share->key_parts + share->keys) * sizeof(HA_KEYSEG),
150
DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
231
151
keydef= *keydef_out;
232
152
recinfo= *recinfo_out;
233
for (i= 0; i < share->sizeKeys(); i++)
153
pos= table_arg->key_info;
154
for (i= 0; i < share->keys; i++, pos++)
235
KeyInfo *pos= &table_arg->key_info[i];
236
keydef[i].flag= ((uint16_t) pos->flags & (HA_NOSAME));
237
keydef[i].key_alg= HA_KEY_ALG_BTREE;
156
keydef[i].flag= ((uint16) pos->flags & (HA_NOSAME | HA_FULLTEXT ));
157
keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ? (HA_KEY_ALG_BTREE) : pos->algorithm;
238
158
keydef[i].block_length= pos->block_size;
239
159
keydef[i].seg= keyseg;
240
160
keydef[i].keysegs= pos->key_parts;
245
DBUG_PRINT("loop", ("found: 0x%lx recpos: %d minpos: %d length: %d",
246
(long) found, recpos, minpos, length));
321
247
if (recpos != minpos)
322
248
{ // Reserved space (Null bits?)
323
memset(recinfo_pos, 0, sizeof(*recinfo_pos));
249
bzero((char*) recinfo_pos, sizeof(*recinfo_pos));
324
250
recinfo_pos->type= (int) FIELD_NORMAL;
325
recinfo_pos++->length= (uint16_t) (minpos - recpos);
251
recinfo_pos++->length= (uint16) (minpos - recpos);
330
256
if (found->flags & BLOB_FLAG)
331
257
recinfo_pos->type= (int) FIELD_BLOB;
332
else if (found->type() == DRIZZLE_TYPE_VARCHAR)
258
else if (found->type() == MYSQL_TYPE_VARCHAR)
333
259
recinfo_pos->type= FIELD_VARCHAR;
334
260
else if (!(options & HA_OPTION_PACK_RECORD))
335
261
recinfo_pos->type= (int) FIELD_NORMAL;
336
262
else if (found->zero_pack())
337
263
recinfo_pos->type= (int) FIELD_SKIP_ZERO;
339
recinfo_pos->type= (int) ((length <= 3) ? FIELD_NORMAL : FIELD_SKIP_PRESPACE);
265
recinfo_pos->type= (int) ((length <= 3 ||
266
(found->flags & ZEROFILL_FLAG)) ?
268
found->type() == MYSQL_TYPE_STRING ||
269
found->type() == MYSQL_TYPE_VAR_STRING ?
270
FIELD_SKIP_ENDSPACE :
271
FIELD_SKIP_PRESPACE);
340
272
if (found->null_ptr)
342
274
recinfo_pos->null_bit= found->null_bit;
343
275
recinfo_pos->null_pos= (uint) (found->null_ptr -
344
(unsigned char*) table_arg->getInsertRecord());
276
(uchar*) table_arg->record[0]);
348
280
recinfo_pos->null_bit= 0;
349
281
recinfo_pos->null_pos= 0;
351
(recinfo_pos++)->length= (uint16_t) length;
283
(recinfo_pos++)->length= (uint16) length;
352
284
recpos= minpos + length;
285
DBUG_PRINT("loop", ("length: %d type: %d",
286
recinfo_pos[-1].length,recinfo_pos[-1].type));
354
288
*records_out= (uint) (recinfo_pos - recinfo);
358
int ha_myisam::reset_auto_increment(uint64_t value)
360
file->s->state.auto_increment= value;
365
294
Check for underlying table conformance
401
330
(should be corretly detected in table2myisam).
404
static int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
405
uint32_t t1_keys, uint32_t t1_recs,
406
MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
407
uint32_t t2_keys, uint32_t t2_recs, bool strict)
333
int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
334
uint t1_keys, uint t1_recs,
335
MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
336
uint t2_keys, uint t2_recs, bool strict)
339
DBUG_ENTER("check_definition");
410
340
if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys))
342
DBUG_PRINT("error", ("Number of keys differs: t1_keys=%u, t2_keys=%u",
414
346
if (t1_recs != t2_recs)
348
DBUG_PRINT("error", ("Number of recs differs: t1_recs=%u, t2_recs=%u",
418
352
for (i= 0; i < t1_keys; i++)
420
354
HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg;
421
355
HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg;
356
if (t1_keyinfo[i].flag & HA_FULLTEXT && t2_keyinfo[i].flag & HA_FULLTEXT)
358
else if (t1_keyinfo[i].flag & HA_FULLTEXT ||
359
t2_keyinfo[i].flag & HA_FULLTEXT)
361
DBUG_PRINT("error", ("Key %d has different definition", i));
362
DBUG_PRINT("error", ("t1_fulltext= %d, t2_fulltext=%d",
363
test(t1_keyinfo[i].flag & HA_FULLTEXT),
364
test(t2_keyinfo[i].flag & HA_FULLTEXT)));
367
if (t1_keyinfo[i].flag & HA_SPATIAL && t2_keyinfo[i].flag & HA_SPATIAL)
369
else if (t1_keyinfo[i].flag & HA_SPATIAL ||
370
t2_keyinfo[i].flag & HA_SPATIAL)
372
DBUG_PRINT("error", ("Key %d has different definition", i));
373
DBUG_PRINT("error", ("t1_spatial= %d, t2_spatial=%d",
374
test(t1_keyinfo[i].flag & HA_SPATIAL),
375
test(t2_keyinfo[i].flag & HA_SPATIAL)));
422
378
if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs ||
423
379
t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg)
381
DBUG_PRINT("error", ("Key %d has different definition", i));
382
DBUG_PRINT("error", ("t1_keysegs=%d, t1_key_alg=%d",
383
t1_keyinfo[i].keysegs, t1_keyinfo[i].key_alg));
384
DBUG_PRINT("error", ("t2_keysegs=%d, t2_key_alg=%d",
385
t2_keyinfo[i].keysegs, t2_keyinfo[i].key_alg));
427
388
for (j= t1_keyinfo[i].keysegs; j--;)
429
uint8_t t1_keysegs_j__type= t1_keysegs[j].type;
390
uint8 t1_keysegs_j__type= t1_keysegs[j].type;
432
393
Table migration from 4.1 to 5.1. In 5.1 a *TEXT key part is
528
507
void _mi_report_crashed(MI_INFO *file, const char *message,
529
const char *sfile, uint32_t sline)
508
const char *sfile, uint sline)
531
Session *cur_session;
532
if ((cur_session= file->in_use))
533
errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from thread_id=%"PRIu64", %s:%d"),
534
cur_session->thread_id,
513
pthread_mutex_lock(&file->s->intern_lock);
514
if ((cur_thd= (THD*) file->in_use.data))
515
sql_print_error("Got an error from thread_id=%lu, %s:%d", cur_thd->thread_id,
537
errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from unknown thread, %s:%d"), sfile, sline);
518
sql_print_error("Got an error from unknown thread, %s:%d", sfile, sline);
539
errmsg_printf(ERRMSG_LVL_ERROR, "%s", message);
540
list<Session *>::iterator it= file->s->in_use->begin();
541
while (it != file->s->in_use->end())
520
sql_print_error("%s", message);
521
for (element= file->s->in_use; element; element= list_rest(element))
543
errmsg_printf(ERRMSG_LVL_ERROR, "%s", _("Unknown thread accessing table"));
523
THD *thd= (THD*) element->data;
524
sql_print_error("%s", thd ? thd_security_context(thd, buf, sizeof(buf), 0)
525
: "Unknown thread accessing table");
548
ha_myisam::ha_myisam(plugin::StorageEngine &engine_arg,
550
: Cursor(engine_arg, table_arg),
552
can_enable_indexes(true),
556
Cursor *ha_myisam::clone(memory::Root *mem_root)
527
pthread_mutex_unlock(&file->s->intern_lock);
532
ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
533
:handler(hton, table_arg), file(0),
534
int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
535
HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
536
HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
537
HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS |
538
HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS |
539
HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT |
540
HA_NEED_READ_RANGE_BUFFER | HA_MRR_CANT_SORT),
541
can_enable_indexes(1)
544
handler *ha_myisam::clone(MEM_ROOT *mem_root)
558
ha_myisam *new_handler= static_cast <ha_myisam *>(Cursor::clone(mem_root));
546
ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(mem_root));
560
548
new_handler->file->state= file->state;
561
549
return new_handler;
564
const char *ha_myisam::index_type(uint32_t )
553
static const char *ha_myisam_exts[] = {
559
const char **ha_myisam::bas_ext() const
561
return ha_myisam_exts;
565
const char *ha_myisam::index_type(uint key_number __attribute__((__unused__)))
569
570
/* Name is here without an extension */
570
int ha_myisam::doOpen(const drizzled::TableIdentifier &identifier, int mode, uint32_t test_if_locked)
571
int ha_myisam::open(const char *name, int mode, uint test_if_locked)
572
573
MI_KEYDEF *keyinfo;
573
574
MI_COLUMNDEF *recinfo= 0;
578
579
If the user wants to have memory mapped data files, add an
589
590
open of a table that is in use by other threads already (if the
590
591
MyISAM share exists already).
592
if (!(file= mi_open(identifier, mode, test_if_locked)))
593
return (errno ? errno : -1);
595
if (!getTable()->getShare()->getType()) /* No need to perform a check for tmp table */
593
if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
594
return (my_errno ? my_errno : -1);
595
if (!table->s->tmp_table) /* No need to perform a check for tmp table */
597
if ((errno= table2myisam(getTable(), &keyinfo, &recinfo, &recs)))
597
if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
599
/* purecov: begin inspected */
600
DBUG_PRINT("error", ("Failed to convert TABLE object to MyISAM "
601
"key and column definition"));
601
if (check_definition(keyinfo, recinfo, getTable()->getShare()->sizeKeys(), recs,
605
if (check_definition(keyinfo, recinfo, table->s->keys, recs,
602
606
file->s->keyinfo, file->s->rec,
603
607
file->s->base.keys, file->s->base.fields, true))
605
errno= HA_ERR_CRASHED;
609
/* purecov: begin inspected */
610
my_errno= HA_ERR_CRASHED;
610
assert(test_if_locked);
611
616
if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
612
mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0);
617
VOID(mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0));
614
619
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
615
620
if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
616
mi_extra(file, HA_EXTRA_WAIT_LOCK, 0);
617
if (!getTable()->getShare()->db_record_offset)
621
keys_with_parts.reset();
622
for (i= 0; i < getTable()->getShare()->sizeKeys(); i++)
621
VOID(mi_extra(file, HA_EXTRA_WAIT_LOCK, 0));
622
if (!table->s->db_record_offset)
623
int_table_flags|=HA_REC_NOT_IN_SEQ;
624
if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
625
int_table_flags|=HA_HAS_CHECKSUM;
627
keys_with_parts.clear_all();
628
for (i= 0; i < table->s->keys; i++)
624
getTable()->key_info[i].block_size= file->s->keyinfo[i].block_length;
630
table->key_info[i].block_size= file->s->keyinfo[i].block_length;
626
KeyPartInfo *kp= getTable()->key_info[i].key_part;
627
KeyPartInfo *kp_end= kp + getTable()->key_info[i].key_parts;
632
KEY_PART_INFO *kp= table->key_info[i].key_part;
633
KEY_PART_INFO *kp_end= kp + table->key_info[i].key_parts;
628
634
for (; kp != kp_end; kp++)
630
if (!kp->field->part_of_key.test(i))
636
if (!kp->field->part_of_key.is_set(i))
632
keys_with_parts.set(i);
638
keys_with_parts.set_bit(i);
643
Both recinfo and keydef are allocated by multi_malloc(), thus only
649
Both recinfo and keydef are allocated by my_multi_malloc(), thus only
644
650
recinfo must be freed.
647
free((unsigned char*) recinfo);
653
my_free((uchar*) recinfo, MYF(0));
651
657
int ha_myisam::close(void)
670
682
return mi_write(file,buf);
674
int ha_myisam::repair(Session *session, MI_CHECK ¶m, bool do_optimize)
677
uint32_t local_testflag= param.testflag;
685
int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
687
if (!file) return HA_ADMIN_INTERNAL_ERROR;
690
MYISAM_SHARE* share = file->s;
691
const char *old_proc_info=thd->proc_info;
693
thd_proc_info(thd, "Checking table");
694
myisamchk_init(¶m);
696
param.op_name = "check";
697
param.db_name= table->s->db.str;
698
param.table_name= table->alias;
699
param.testflag = check_opt->flags | T_CHECK | T_SILENT;
700
param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
702
if (!(table->db_stat & HA_READ_ONLY))
703
param.testflag|= T_STATISTICS;
704
param.using_global_keycache = 1;
706
if (!mi_is_crashed(file) &&
707
(((param.testflag & T_CHECK_ONLY_CHANGED) &&
708
!(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
709
STATE_CRASHED_ON_REPAIR)) &&
710
share->state.open_count == 0) ||
711
((param.testflag & T_FAST) && (share->state.open_count ==
712
(uint) (share->global_changed ? 1 : 0)))))
713
return HA_ADMIN_ALREADY_DONE;
715
error = chk_status(¶m, file); // Not fatal
716
error = chk_size(¶m, file);
718
error |= chk_del(¶m, file, param.testflag);
720
error = chk_key(¶m, file);
723
if ((!(param.testflag & T_QUICK) &&
725
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
726
(param.testflag & (T_EXTEND | T_MEDIUM)))) ||
729
uint old_testflag=param.testflag;
730
param.testflag|=T_MEDIUM;
731
if (!(error= init_io_cache(¶m.read_cache, file->dfile,
732
my_default_record_cache_size, READ_CACHE,
733
share->pack.header_length, 1, MYF(MY_WME))))
735
error= chk_data_link(¶m, file, param.testflag & T_EXTEND);
736
end_io_cache(&(param.read_cache));
738
param.testflag= old_testflag;
743
if ((share->state.changed & (STATE_CHANGED |
744
STATE_CRASHED_ON_REPAIR |
745
STATE_CRASHED | STATE_NOT_ANALYZED)) ||
746
(param.testflag & T_STATISTICS) ||
749
file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
750
pthread_mutex_lock(&share->intern_lock);
751
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
752
STATE_CRASHED_ON_REPAIR);
753
if (!(table->db_stat & HA_READ_ONLY))
754
error=update_state_info(¶m,file,UPDATE_TIME | UPDATE_OPEN_COUNT |
756
pthread_mutex_unlock(&share->intern_lock);
757
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
761
else if (!mi_is_crashed(file) && !thd->killed)
763
mi_mark_crashed(file);
764
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
767
thd_proc_info(thd, old_proc_info);
768
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
773
analyze the key distribution in the table
774
As the table may be only locked for read, we have to take into account that
775
two threads may do an analyze at the same time!
778
int ha_myisam::analyze(THD *thd,
779
HA_CHECK_OPT* check_opt __attribute__((__unused__)))
783
MYISAM_SHARE* share = file->s;
785
myisamchk_init(¶m);
787
param.op_name= "analyze";
788
param.db_name= table->s->db.str;
789
param.table_name= table->alias;
790
param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
791
T_DONT_CHECK_CHECKSUM);
792
param.using_global_keycache = 1;
793
param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
795
if (!(share->state.changed & STATE_NOT_ANALYZED))
796
return HA_ADMIN_ALREADY_DONE;
798
error = chk_key(¶m, file);
801
pthread_mutex_lock(&share->intern_lock);
802
error=update_state_info(¶m,file,UPDATE_STAT);
803
pthread_mutex_unlock(&share->intern_lock);
805
else if (!mi_is_crashed(file) && !thd->killed)
806
mi_mark_crashed(file);
807
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
811
int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
815
ha_rows start_records;
817
if (!file) return HA_ADMIN_INTERNAL_ERROR;
819
myisamchk_init(¶m);
821
param.op_name= "repair";
822
param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
823
T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
824
(check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
825
param.sort_buffer_length= check_opt->sort_buffer_size;
826
start_records=file->state->records;
827
while ((error=repair(thd,param,0)) && param.retry_repair)
829
param.retry_repair=0;
830
if (test_all_bits(param.testflag,
831
(uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
833
param.testflag&= ~T_RETRY_WITHOUT_QUICK;
834
sql_print_information("Retrying repair of: '%s' without quick",
838
param.testflag&= ~T_QUICK;
839
if ((param.testflag & T_REP_BY_SORT))
841
param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
842
sql_print_information("Retrying repair of: '%s' with keycache",
848
if (!error && start_records != file->state->records &&
849
!(check_opt->flags & T_VERY_SILENT))
851
char llbuff[22],llbuff2[22];
852
sql_print_information("Found %s of %s rows when repairing '%s'",
853
llstr(file->state->records, llbuff),
854
llstr(start_records, llbuff2),
860
int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
863
if (!file) return HA_ADMIN_INTERNAL_ERROR;
866
myisamchk_init(¶m);
868
param.op_name= "optimize";
869
param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
870
T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
871
param.sort_buffer_length= check_opt->sort_buffer_size;
872
if ((error= repair(thd,param,1)) && param.retry_repair)
874
sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying",
875
my_errno, param.db_name, param.table_name);
876
param.testflag&= ~T_REP_BY_SORT;
877
error= repair(thd,param,1);
883
int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_optimize)
886
uint local_testflag=param.testflag;
678
887
bool optimize_done= !do_optimize, statistics_done=0;
679
const char *old_proc_info= session->get_proc_info();
888
const char *old_proc_info=thd->proc_info;
680
889
char fixed_name[FN_REFLEN];
681
890
MYISAM_SHARE* share = file->s;
682
891
ha_rows rows= file->state->records;
892
DBUG_ENTER("ha_myisam::repair");
685
895
Normally this method is entered with a properly opened table. If the
721
932
uint64_t key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
722
933
mi_get_mask_all_keys_active(share->base.keys) :
723
934
share->state.key_map);
724
uint32_t testflag=param.testflag;
935
uint testflag=param.testflag;
725
936
if (mi_test_if_sort_rep(file,file->state->records,key_map,0) &&
726
937
(local_testflag & T_REP_BY_SORT))
728
939
local_testflag|= T_STATISTICS;
729
940
param.testflag|= T_STATISTICS; // We get this for free
730
941
statistics_done=1;
732
session->set_proc_info("Repair by sorting");
942
if (thd->variables.myisam_repair_threads>1)
945
/* TODO: respect myisam_repair_threads variable */
946
snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
947
thd_proc_info(thd, buf);
948
error = mi_repair_parallel(¶m, file, fixed_name,
949
param.testflag & T_QUICK);
950
thd_proc_info(thd, "Repair done"); // to reset proc_info, as
951
// it was pointing to local buffer
955
thd_proc_info(thd, "Repair by sorting");
733
956
error = mi_repair_by_sort(¶m, file, fixed_name,
734
957
param.testflag & T_QUICK);
739
session->set_proc_info("Repair with keycache");
962
thd_proc_info(thd, "Repair with keycache");
740
963
param.testflag &= ~T_REP_BY_SORT;
741
964
error= mi_repair(¶m, file, fixed_name,
742
965
param.testflag & T_QUICK);
803
1026
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
804
1027
update_state_info(¶m, file, 0);
806
session->set_proc_info(old_proc_info);
807
mi_lock_database(file,F_UNLCK);
809
return(error ? HA_ADMIN_FAILED :
1029
thd_proc_info(thd, old_proc_info);
1030
if (!thd->locked_tables)
1031
mi_lock_database(file,F_UNLCK);
1032
DBUG_RETURN(error ? HA_ADMIN_FAILED :
810
1033
!optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
1038
Assign table indexes to a specific key cache.
1041
int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
1043
KEY_CACHE *new_key_cache= check_opt->key_cache;
1044
const char *errmsg= 0;
1045
int error= HA_ADMIN_OK;
1047
TABLE_LIST *table_list= table->pos_in_table_list;
1048
DBUG_ENTER("ha_myisam::assign_to_keycache");
1050
table->keys_in_use_for_query.clear_all();
1052
if (table_list->process_index_hints(table))
1053
DBUG_RETURN(HA_ADMIN_FAILED);
1055
if (!table->keys_in_use_for_query.is_clear_all())
1056
/* use all keys if there's no list specified by the user through hints */
1057
map= table->keys_in_use_for_query.to_uint64_t();
1059
if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
1061
char buf[STRING_BUFFER_USUAL_SIZE];
1062
snprintf(buf, sizeof(buf),
1063
"Failed to flush to index file (errno: %d)", error);
1065
error= HA_ADMIN_CORRUPT;
1068
if (error != HA_ADMIN_OK)
1070
/* Send error to user */
1072
myisamchk_init(¶m);
1074
param.op_name= "assign_to_keycache";
1075
param.db_name= table->s->db.str;
1076
param.table_name= table->s->table_name.str;
1078
mi_check_print_error(¶m, errmsg);
815
1085
Disable indexes, making it persistent if requested.
905
1175
else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
907
Session *session= getTable()->in_use;
908
boost::scoped_ptr<MI_CHECK> param_ap(new MI_CHECK);
909
MI_CHECK ¶m= *param_ap.get();
910
const char *save_proc_info= session->get_proc_info();
911
session->set_proc_info("Creating index");
1177
THD *thd=current_thd;
1179
const char *save_proc_info=thd->proc_info;
1180
thd_proc_info(thd, "Creating index");
912
1181
myisamchk_init(¶m);
913
1182
param.op_name= "recreating_index";
914
1183
param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
915
1184
T_CREATE_MISSING_KEYS);
916
1185
param.myf_rw&= ~MY_WAIT_IF_FULL;
917
param.sort_buffer_length= static_cast<size_t>(sort_buffer_size);
918
param.stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
919
if ((error= (repair(session,param,0) != HA_ADMIN_OK)) && param.retry_repair)
1186
param.sort_buffer_length= thd->variables.myisam_sort_buff_size;
1187
param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
1188
param.tmpdir=&mysql_tmpdir_list;
1189
if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair)
921
errmsg_printf(ERRMSG_LVL_WARN, "Warning: Enabling keys got errno %d on %s.%s, retrying",
922
errno, param.db_name, param.table_name);
1191
sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, retrying",
1192
my_errno, param.db_name, param.table_name);
923
1193
/* Repairing by sort failed. Now try standard repair method. */
924
1194
param.testflag&= ~(T_REP_BY_SORT | T_QUICK);
925
error= (repair(session,param,0) != HA_ADMIN_OK);
1195
error= (repair(thd,param,0) != HA_ADMIN_OK);
927
1197
If the standard repair succeeded, clear all error messages which
928
1198
might have been set by the first repair. They can still be seen
929
1199
with SHOW WARNINGS then.
932
session->clear_error();
934
1204
info(HA_STATUS_CONST);
935
session->set_proc_info(save_proc_info);
1205
thd_proc_info(thd, save_proc_info);
1036
int ha_myisam::doUpdateRecord(const unsigned char *old_data, unsigned char *new_data)
1311
bool ha_myisam::check_and_repair(THD *thd)
1316
uint old_query_length;
1317
HA_CHECK_OPT check_opt;
1318
DBUG_ENTER("ha_myisam::check_and_repair");
1321
check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
1322
// Don't use quick if deleted rows
1323
if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
1324
check_opt.flags|=T_QUICK;
1325
sql_print_warning("Checking table: '%s'",table->s->path.str);
1327
old_query= thd->query;
1328
old_query_length= thd->query_length;
1329
pthread_mutex_lock(&LOCK_thread_count);
1330
thd->query= table->s->table_name.str;
1331
thd->query_length= table->s->table_name.length;
1332
pthread_mutex_unlock(&LOCK_thread_count);
1334
if ((marked_crashed= mi_is_crashed(file)) || check(thd, &check_opt))
1336
sql_print_warning("Recovering table: '%s'",table->s->path.str);
1338
((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
1339
(marked_crashed ? 0 : T_QUICK) |
1340
(myisam_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
1342
if (repair(thd, &check_opt))
1345
pthread_mutex_lock(&LOCK_thread_count);
1346
thd->query= old_query;
1347
thd->query_length= old_query_length;
1348
pthread_mutex_unlock(&LOCK_thread_count);
1352
bool ha_myisam::is_crashed() const
1354
return (file->s->state.changed & STATE_CRASHED ||
1355
(my_disable_locking && file->s->state.open_count));
1358
int ha_myisam::update_row(const uchar *old_data, uchar *new_data)
1360
ha_statistic_increment(&SSV::ha_update_count);
1361
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
1362
table->timestamp_field->set_time();
1038
1363
return mi_update(file,old_data,new_data);
1041
int ha_myisam::doDeleteRecord(const unsigned char *buf)
1366
int ha_myisam::delete_row(const uchar *buf)
1368
ha_statistic_increment(&SSV::ha_delete_count);
1043
1369
return mi_delete(file,buf);
1047
int ha_myisam::doStartIndexScan(uint32_t idx, bool )
1374
my_bool index_cond_func_myisam(void *arg)
1376
ha_myisam *h= (ha_myisam*)arg;
1377
/*if (h->in_range_read)*/
1380
if (h->compare_key2(h->end_range) > 0)
1381
return 2; /* caller should return HA_ERR_END_OF_FILE already */
1383
return (my_bool)h->pushed_idx_cond->val_int();
1389
int ha_myisam::index_init(uint idx, bool sorted __attribute__((__unused__)))
1049
1391
active_index=idx;
1050
//in_range_read= false;
1392
//in_range_read= FALSE;
1393
if (pushed_idx_cond_keyno == idx)
1394
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1055
int ha_myisam::doEndIndexScan()
1399
int ha_myisam::index_end()
1057
1401
active_index=MAX_KEY;
1402
//pushed_idx_cond_keyno= MAX_KEY;
1403
mi_set_index_cond_func(file, NULL, 0);
1404
in_range_check_pushed_down= FALSE;
1405
ds_mrr.dsmrr_close();
1062
int ha_myisam::index_read_map(unsigned char *buf, const unsigned char *key,
1410
int ha_myisam::index_read_map(uchar *buf, const uchar *key,
1063
1411
key_part_map keypart_map,
1064
1412
enum ha_rkey_function find_flag)
1066
assert(inited==INDEX);
1067
ha_statistic_increment(&system_status_var::ha_read_key_count);
1414
DBUG_ASSERT(inited==INDEX);
1415
ha_statistic_increment(&SSV::ha_read_key_count);
1068
1416
int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
1069
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1417
table->status=error ? STATUS_NOT_FOUND: 0;
1073
int ha_myisam::index_read_idx_map(unsigned char *buf, uint32_t index, const unsigned char *key,
1421
int ha_myisam::index_read_idx_map(uchar *buf, uint index, const uchar *key,
1074
1422
key_part_map keypart_map,
1075
1423
enum ha_rkey_function find_flag)
1077
ha_statistic_increment(&system_status_var::ha_read_key_count);
1425
ha_statistic_increment(&SSV::ha_read_key_count);
1078
1426
int error=mi_rkey(file, buf, index, key, keypart_map, find_flag);
1079
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1427
table->status=error ? STATUS_NOT_FOUND: 0;
1083
int ha_myisam::index_read_last_map(unsigned char *buf, const unsigned char *key,
1431
int ha_myisam::index_read_last_map(uchar *buf, const uchar *key,
1084
1432
key_part_map keypart_map)
1086
assert(inited==INDEX);
1087
ha_statistic_increment(&system_status_var::ha_read_key_count);
1434
DBUG_ENTER("ha_myisam::index_read_last");
1435
DBUG_ASSERT(inited==INDEX);
1436
ha_statistic_increment(&SSV::ha_read_key_count);
1088
1437
int error=mi_rkey(file, buf, active_index, key, keypart_map,
1089
1438
HA_READ_PREFIX_LAST);
1090
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1439
table->status=error ? STATUS_NOT_FOUND: 0;
1094
int ha_myisam::index_next(unsigned char *buf)
1443
int ha_myisam::index_next(uchar *buf)
1096
assert(inited==INDEX);
1097
ha_statistic_increment(&system_status_var::ha_read_next_count);
1445
DBUG_ASSERT(inited==INDEX);
1446
ha_statistic_increment(&SSV::ha_read_next_count);
1098
1447
int error=mi_rnext(file,buf,active_index);
1099
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1448
table->status=error ? STATUS_NOT_FOUND: 0;
1103
int ha_myisam::index_prev(unsigned char *buf)
1452
int ha_myisam::index_prev(uchar *buf)
1105
assert(inited==INDEX);
1106
ha_statistic_increment(&system_status_var::ha_read_prev_count);
1454
DBUG_ASSERT(inited==INDEX);
1455
ha_statistic_increment(&SSV::ha_read_prev_count);
1107
1456
int error=mi_rprev(file,buf, active_index);
1108
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1457
table->status=error ? STATUS_NOT_FOUND: 0;
1112
int ha_myisam::index_first(unsigned char *buf)
1461
int ha_myisam::index_first(uchar *buf)
1114
assert(inited==INDEX);
1115
ha_statistic_increment(&system_status_var::ha_read_first_count);
1463
DBUG_ASSERT(inited==INDEX);
1464
ha_statistic_increment(&SSV::ha_read_first_count);
1116
1465
int error=mi_rfirst(file, buf, active_index);
1117
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1466
table->status=error ? STATUS_NOT_FOUND: 0;
1121
int ha_myisam::index_last(unsigned char *buf)
1470
int ha_myisam::index_last(uchar *buf)
1123
assert(inited==INDEX);
1124
ha_statistic_increment(&system_status_var::ha_read_last_count);
1472
DBUG_ASSERT(inited==INDEX);
1473
ha_statistic_increment(&SSV::ha_read_last_count);
1125
1474
int error=mi_rlast(file, buf, active_index);
1126
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1475
table->status=error ? STATUS_NOT_FOUND: 0;
1130
int ha_myisam::index_next_same(unsigned char *buf,
1131
const unsigned char *,
1479
int ha_myisam::index_next_same(uchar *buf,
1480
const uchar *key __attribute__((unused)),
1481
uint length __attribute__((unused)))
1135
assert(inited==INDEX);
1136
ha_statistic_increment(&system_status_var::ha_read_next_count);
1484
DBUG_ASSERT(inited==INDEX);
1485
ha_statistic_increment(&SSV::ha_read_next_count);
1139
1488
error= mi_rnext_same(file,buf);
1140
1489
} while (error == HA_ERR_RECORD_DELETED);
1141
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1490
table->status=error ? STATUS_NOT_FOUND: 0;
1151
1500
//if (!eq_range_arg)
1152
// in_range_read= true;
1501
// in_range_read= TRUE;
1154
res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
1503
res= handler::read_range_first(start_key, end_key, eq_range_arg, sorted);
1157
// in_range_read= false;
1506
// in_range_read= FALSE;
1162
1511
int ha_myisam::read_range_next()
1164
int res= Cursor::read_range_next();
1513
int res= handler::read_range_next();
1166
// in_range_read= false;
1515
// in_range_read= FALSE;
1171
int ha_myisam::doStartTableScan(bool scan)
1520
int ha_myisam::rnd_init(bool scan)
1174
1523
return mi_scan_init(file);
1175
1524
return mi_reset(file); // Free buffers
1178
int ha_myisam::rnd_next(unsigned char *buf)
1527
int ha_myisam::rnd_next(uchar *buf)
1180
ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
1529
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1181
1530
int error=mi_scan(file, buf);
1182
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1186
int ha_myisam::rnd_pos(unsigned char *buf, unsigned char *pos)
1188
ha_statistic_increment(&system_status_var::ha_read_rnd_count);
1189
int error=mi_rrnd(file, buf, internal::my_get_ptr(pos,ref_length));
1190
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1195
void ha_myisam::position(const unsigned char *)
1197
internal::my_off_t row_position= mi_position(file);
1198
internal::my_store_ptr(ref, ref_length, row_position);
1201
int ha_myisam::info(uint32_t flag)
1531
table->status=error ? STATUS_NOT_FOUND: 0;
1535
int ha_myisam::restart_rnd_next(uchar *buf, uchar *pos)
1537
return rnd_pos(buf,pos);
1540
int ha_myisam::rnd_pos(uchar *buf, uchar *pos)
1542
ha_statistic_increment(&SSV::ha_read_rnd_count);
1543
int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
1544
table->status=error ? STATUS_NOT_FOUND: 0;
1549
void ha_myisam::position(const uchar *record __attribute__((__unused__)))
1551
my_off_t row_position= mi_position(file);
1552
my_store_ptr(ref, ref_length, row_position);
1555
int ha_myisam::info(uint flag)
1203
1557
MI_ISAMINFO misam_info;
1204
1558
char name_buff[FN_REFLEN];
1217
1571
if (flag & HA_STATUS_CONST)
1219
TableShare *share= getTable()->getMutableShare();
1573
TABLE_SHARE *share= table->s;
1220
1574
stats.max_data_file_length= misam_info.max_data_file_length;
1221
1575
stats.max_index_file_length= misam_info.max_index_file_length;
1222
1576
stats.create_time= misam_info.create_time;
1223
1577
ref_length= misam_info.reflength;
1224
1578
share->db_options_in_use= misam_info.options;
1225
stats.block_size= myisam_key_cache_block_size; /* record block size */
1579
stats.block_size= myisam_block_size; /* record block size */
1227
set_prefix(share->keys_in_use, share->sizeKeys());
1229
* Due to bug 394932 (32-bit solaris build failure), we need
1230
* to convert the uint64_t key_map member of the misam_info
1231
* structure in to a std::bitset so that we can logically and
1232
* it with the share->key_in_use key_map.
1235
string binary_key_map;
1236
uint64_t num= misam_info.key_map;
1238
* Convert the uint64_t to a binary
1239
* string representation of it.
1243
uint64_t bin_digit= num % 2;
1247
binary_key_map.append(ostr.str());
1249
* Now we have the binary string representation of the
1250
* flags, we need to fill that string representation out
1251
* with the appropriate number of bits. This is needed
1252
* since key_map is declared as a std::bitset of a certain bit
1253
* width that depends on the MAX_INDEXES variable.
1255
if (MAX_INDEXES <= 64)
1257
size_t len= 72 - binary_key_map.length();
1258
string all_zeros(len, '0');
1259
binary_key_map.insert(binary_key_map.begin(),
1265
size_t len= (MAX_INDEXES + 7) / 8 * 8;
1266
string all_zeros(len, '0');
1267
binary_key_map.insert(binary_key_map.begin(),
1271
key_map tmp_map(binary_key_map);
1272
share->keys_in_use&= tmp_map;
1273
share->keys_for_keyread&= share->keys_in_use;
1582
if (share->tmp_table == NO_TMP_TABLE)
1583
pthread_mutex_lock(&share->mutex);
1584
share->keys_in_use.set_prefix(share->keys);
1585
share->keys_in_use.intersect_extended(misam_info.key_map);
1586
share->keys_for_keyread.intersect(share->keys_in_use);
1274
1587
share->db_record_offset= misam_info.record_offset;
1275
1588
if (share->key_parts)
1276
memcpy(getTable()->key_info[0].rec_per_key,
1277
misam_info.rec_per_key,
1278
sizeof(getTable()->key_info[0].rec_per_key)*share->key_parts);
1279
assert(share->getType() != message::Table::STANDARD);
1589
memcpy((char*) table->key_info[0].rec_per_key,
1590
(char*) misam_info.rec_per_key,
1591
sizeof(table->key_info[0].rec_per_key)*share->key_parts);
1592
if (share->tmp_table == NO_TMP_TABLE)
1593
pthread_mutex_unlock(&share->mutex);
1282
1596
Set data_file_name and index_file_name to point at the symlink value
1283
1597
if table is symlinked (Ie; Real name is not same as generated name)
1285
1599
data_file_name= index_file_name= 0;
1286
internal::fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1600
fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1287
1601
MY_APPEND_EXT | MY_UNPACK_FILENAME);
1288
1602
if (strcmp(name_buff, misam_info.data_file_name))
1289
1603
data_file_name=misam_info.data_file_name;
1290
internal::fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1604
fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1291
1605
MY_APPEND_EXT | MY_UNPACK_FILENAME);
1292
1606
if (strcmp(name_buff, misam_info.index_file_name))
1293
1607
index_file_name=misam_info.index_file_name;
1328
1650
return mi_delete_all_rows(file);
1331
int MyisamEngine::doDropTable(Session &session,
1332
const TableIdentifier &identifier)
1653
int ha_myisam::delete_table(const char *name)
1334
session.getMessageCache().removeTableMessage(identifier);
1336
return mi_delete_table(identifier.getPath().c_str());
1655
return mi_delete_table(name);
1340
int ha_myisam::external_lock(Session *session, int lock_type)
1659
int ha_myisam::external_lock(THD *thd, int lock_type)
1342
file->in_use= session;
1343
return mi_lock_database(file, !getTable()->getShare()->getType() ?
1661
file->in_use.data= thd;
1662
return mi_lock_database(file, !table->s->tmp_table ?
1344
1663
lock_type : ((lock_type == F_UNLCK) ?
1345
1664
F_UNLCK : F_EXTRA_LCK));
1348
int MyisamEngine::doCreateTable(Session &session,
1350
const TableIdentifier &identifier,
1351
message::Table& create_proto)
1667
THR_LOCK_DATA **ha_myisam::store_lock(THD *thd __attribute__((__unused__)),
1669
enum thr_lock_type lock_type)
1671
if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
1672
file->lock.type=lock_type;
1677
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
1679
ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
1680
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
1682
create_info->auto_increment_value= stats.auto_increment_value;
1684
create_info->data_file_name=data_file_name;
1685
create_info->index_file_name=index_file_name;
1689
int ha_myisam::create(const char *name, register TABLE *table_arg,
1690
HA_CREATE_INFO *ha_create_info)
1354
uint32_t create_flags= 0, create_records;
1693
uint create_flags= 0, records, i;
1355
1694
char buff[FN_REFLEN];
1356
1695
MI_KEYDEF *keydef;
1357
1696
MI_COLUMNDEF *recinfo;
1358
1697
MI_CREATE_INFO create_info;
1359
TableShare *share= table_arg.getMutableShare();
1360
uint32_t options= share->db_options_in_use;
1361
if ((error= table2myisam(&table_arg, &keydef, &recinfo, &create_records)))
1363
memset(&create_info, 0, sizeof(create_info));
1364
create_info.max_rows= create_proto.options().max_rows();
1365
create_info.reloc_rows= create_proto.options().min_rows();
1698
TABLE_SHARE *share= table_arg->s;
1699
uint options= share->db_options_in_use;
1700
DBUG_ENTER("ha_myisam::create");
1701
for (i= 0; i < share->keys; i++)
1703
if (table_arg->key_info[i].flags & HA_USES_PARSER)
1705
create_flags|= HA_CREATE_RELIES_ON_SQL_LAYER;
1709
if ((error= table2myisam(table_arg, &keydef, &recinfo, &records)))
1710
DBUG_RETURN(error); /* purecov: inspected */
1711
bzero((char*) &create_info, sizeof(create_info));
1712
create_info.max_rows= share->max_rows;
1713
create_info.reloc_rows= share->min_rows;
1366
1714
create_info.with_auto_increment= share->next_number_key_offset == 0;
1367
create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
1368
create_proto.options().auto_increment_value() -1 :
1715
create_info.auto_increment= (ha_create_info->auto_increment_value ?
1716
ha_create_info->auto_increment_value -1 :
1370
create_info.data_file_length= (create_proto.options().max_rows() *
1371
create_proto.options().avg_row_length());
1372
create_info.data_file_name= NULL;
1373
create_info.index_file_name= NULL;
1718
create_info.data_file_length= ((uint64_t) share->max_rows *
1719
share->avg_row_length);
1720
create_info.data_file_name= ha_create_info->data_file_name;
1721
create_info.index_file_name= ha_create_info->index_file_name;
1374
1722
create_info.language= share->table_charset->number;
1376
if (create_proto.type() == message::Table::TEMPORARY)
1724
if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
1377
1725
create_flags|= HA_CREATE_TMP_TABLE;
1726
if (ha_create_info->options & HA_CREATE_KEEP_FILES)
1727
create_flags|= HA_CREATE_KEEP_FILES;
1378
1728
if (options & HA_OPTION_PACK_RECORD)
1379
1729
create_flags|= HA_PACK_RECORD;
1730
if (options & HA_OPTION_CHECKSUM)
1731
create_flags|= HA_CREATE_CHECKSUM;
1732
if (options & HA_OPTION_DELAY_KEY_WRITE)
1733
create_flags|= HA_CREATE_DELAY_KEY_WRITE;
1381
/* TODO: Check that the following internal::fn_format is really needed */
1382
error= mi_create(internal::fn_format(buff, identifier.getPath().c_str(), "", "",
1383
MY_UNPACK_FILENAME|MY_APPEND_EXT),
1384
share->sizeKeys(), keydef,
1385
create_records, recinfo,
1735
/* TODO: Check that the following fn_format is really needed */
1736
error= mi_create(fn_format(buff, name, "", "",
1737
MY_UNPACK_FILENAME|MY_APPEND_EXT),
1738
share->keys, keydef,
1386
1740
0, (MI_UNIQUEDEF*) 0,
1387
1741
&create_info, create_flags);
1388
free((unsigned char*) recinfo);
1390
session.getMessageCache().storeTableMessage(identifier, create_proto);
1742
my_free((uchar*) recinfo, MYF(0));
1396
int MyisamEngine::doRenameTable(Session &session, const TableIdentifier &from, const TableIdentifier &to)
1747
int ha_myisam::rename_table(const char * from, const char * to)
1398
session.getMessageCache().renameTableMessage(from, to);
1400
return mi_rename(from.getPath().c_str(), to.getPath().c_str());
1749
return mi_rename(from,to);
1404
void ha_myisam::get_auto_increment(uint64_t ,
1753
void ha_myisam::get_auto_increment(uint64_t offset __attribute__((__unused__)),
1754
uint64_t increment __attribute__((__unused__)),
1755
uint64_t nb_desired_values __attribute__((__unused__)),
1407
1756
uint64_t *first_value,
1408
1757
uint64_t *nb_reserved_values)
1412
unsigned char key[MI_MAX_KEY_LENGTH];
1761
uchar key[MI_MAX_KEY_LENGTH];
1414
if (!getTable()->getShare()->next_number_key_offset)
1763
if (!table->s->next_number_key_offset)
1415
1764
{ // Autoincrement at key-start
1416
1765
ha_myisam::info(HA_STATUS_AUTO);
1417
1766
*first_value= stats.auto_increment_value;
1418
1767
/* MyISAM has only table-level lock, so reserves to +inf */
1419
*nb_reserved_values= UINT64_MAX;
1768
*nb_reserved_values= ULONGLONG_MAX;
1423
1772
/* it's safe to call the following if bulk_insert isn't on */
1424
mi_flush_bulk_insert(file, getTable()->getShare()->next_number_index);
1773
mi_flush_bulk_insert(file, table->s->next_number_index);
1426
1775
(void) extra(HA_EXTRA_KEYREAD);
1427
key_copy(key, getTable()->getInsertRecord(),
1428
&getTable()->key_info[getTable()->getShare()->next_number_index],
1429
getTable()->getShare()->next_number_key_offset);
1430
error= mi_rkey(file, getTable()->getUpdateRecord(), (int) getTable()->getShare()->next_number_index,
1431
key, make_prev_keypart_map(getTable()->getShare()->next_number_keypart),
1776
key_copy(key, table->record[0],
1777
table->key_info + table->s->next_number_index,
1778
table->s->next_number_key_offset);
1779
error= mi_rkey(file, table->record[1], (int) table->s->next_number_index,
1780
key, make_prev_keypart_map(table->s->next_number_keypart),
1432
1781
HA_READ_PREFIX_LAST);
1437
/* Get data from getUpdateRecord() */
1438
nr= ((uint64_t) getTable()->next_number_field->
1439
val_int_offset(getTable()->getShare()->rec_buff_length)+1);
1786
/* Get data from record[1] */
1787
nr= ((uint64_t) table->next_number_field->
1788
val_int_offset(table->s->rec_buff_length)+1);
1441
1790
extra(HA_EXTRA_NO_KEYREAD);
1442
1791
*first_value= nr;
1478
ha_rows ha_myisam::records_in_range(uint32_t inx, key_range *min_key,
1827
ha_rows ha_myisam::records_in_range(uint inx, key_range *min_key,
1479
1828
key_range *max_key)
1481
1830
return (ha_rows) mi_records_in_range(file, (int) inx, min_key, max_key);
1485
uint32_t ha_myisam::checksum() const
1834
uint ha_myisam::checksum() const
1487
1836
return (uint)file->state->checksum;
1490
static int myisam_init(module::Context &context)
1492
context.add(new MyisamEngine(engine_name));
1493
context.registerVariable(new sys_var_constrained_value<size_t>("sort-buffer-size",
1495
context.registerVariable(new sys_var_uint64_t_ptr("max_sort_file_size",
1496
&max_sort_file_size,
1497
context.getOptions()["max-sort-file-size"].as<uint64_t>()));
1840
bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
1843
uint options= table->s->db_options_in_use;
1845
if (info->auto_increment_value != stats.auto_increment_value ||
1846
info->data_file_name != data_file_name ||
1847
info->index_file_name != index_file_name ||
1848
table_changes == IS_EQUAL_NO ||
1849
table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
1850
return COMPATIBLE_DATA_NO;
1852
if ((options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1853
HA_OPTION_DELAY_KEY_WRITE)) !=
1854
(info->table_options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1855
HA_OPTION_DELAY_KEY_WRITE)))
1856
return COMPATIBLE_DATA_NO;
1857
return COMPATIBLE_DATA_YES;
1860
int myisam_panic(handlerton *hton __attribute__((__unused__)), ha_panic_function flag)
1862
return mi_panic(flag);
1865
static int myisam_init(void *p)
1867
handlerton *myisam_hton;
1869
myisam_hton= (handlerton *)p;
1870
myisam_hton->state= SHOW_OPTION_YES;
1871
myisam_hton->db_type= DB_TYPE_MYISAM;
1872
myisam_hton->create= myisam_create_handler;
1873
myisam_hton->panic= myisam_panic;
1874
myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
1503
static void init_options(drizzled::module::option_context &context)
1505
context("max-sort-file-size",
1506
po::value<uint64_t>(&max_sort_file_size)->default_value(INT32_MAX),
1507
N_("Don't use the fast sort index method to created index if the temporary file would get bigger than this."));
1508
context("sort-buffer-size",
1509
po::value<sort_buffer_constraint>(&sort_buffer_size)->default_value(8192*1024),
1510
N_("The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE."));
1514
DRIZZLE_DECLARE_PLUGIN
1880
/****************************************************************************
1881
* MyISAM MRR implementation: use DS-MRR
1882
***************************************************************************/
1884
int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
1885
uint n_ranges, uint mode,
1886
HANDLER_BUFFER *buf)
1888
return ds_mrr.dsmrr_init(this, &table->key_info[active_index],
1889
seq, seq_init_param, n_ranges, mode, buf);
1892
int ha_myisam::multi_range_read_next(char **range_info)
1894
return ds_mrr.dsmrr_next(this, range_info);
1897
ha_rows ha_myisam::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
1898
void *seq_init_param,
1899
uint n_ranges, uint *bufsz,
1900
uint *flags, COST_VECT *cost)
1903
This call is here because there is no location where this->table would
1905
TODO: consider moving it into some per-query initialization call.
1907
ds_mrr.init(this, table);
1908
return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz,
1912
int ha_myisam::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
1913
uint *bufsz, uint *flags, COST_VECT *cost)
1915
ds_mrr.init(this, table);
1916
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
1919
/* MyISAM MRR implementation ends */
1922
/* Index condition pushdown implementation*/
1925
Item *ha_myisam::idx_cond_push(uint keyno_arg, Item* idx_cond_arg)
1927
pushed_idx_cond_keyno= keyno_arg;
1928
pushed_idx_cond= idx_cond_arg;
1929
in_range_check_pushed_down= TRUE;
1930
if (active_index == pushed_idx_cond_keyno)
1931
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1936
struct st_mysql_storage_engine myisam_storage_engine=
1937
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
1939
mysql_declare_plugin(myisam)
1941
MYSQL_STORAGE_ENGINE_PLUGIN,
1942
&myisam_storage_engine,
1520
1945
"Default engine as of MySQL 3.23 with great performance",
1521
1946
PLUGIN_LICENSE_GPL,
1522
1947
myisam_init, /* Plugin Init */
1523
NULL, /* system variables */
1524
init_options /* config options */
1526
DRIZZLE_DECLARE_PLUGIN_END;
1948
NULL, /* Plugin Deinit */
1950
NULL, /* status variables */
1951
NULL, /* system variables */
1952
NULL /* config options */
1954
mysql_declare_plugin_end;
1957
#ifdef HAVE_QUERY_CACHE
1959
@brief Register a named table with a call back function to the query cache.
1961
@param thd The thread handle
1962
@param table_key A pointer to the table name in the table cache
1963
@param key_length The length of the table name
1964
@param[out] engine_callback The pointer to the storage engine call back
1965
function, currently 0
1966
@param[out] engine_data Engine data will be set to 0.
1968
@note Despite the name of this function, it is used to check each statement
1969
before it is cached and not to register a table or callback function.
1971
@see handler::register_query_cache_table
1973
@return The error code. The engine_data and engine_callback will be set to 0.
1974
@retval TRUE Success
1975
@retval FALSE An error occured
1978
my_bool ha_myisam::register_query_cache_table(THD *thd, char *table_name,
1979
uint table_name_len,
1982
uint64_t *engine_data)
1984
DBUG_ENTER("ha_myisam::register_query_cache_table");
1986
No call back function is needed to determine if a cached statement
1989
*engine_callback= 0;
1992
No engine data is needed.
1996
if (file->s->concurrent_insert)
1999
If a concurrent INSERT has happened just before the currently
2000
processed SELECT statement, the total size of the table is
2003
To determine if the table size is known, the current thread's snap
2004
shot of the table size with the actual table size are compared.
2006
If the table size is unknown the SELECT statement can't be cached.
2008
When concurrent inserts are disabled at table open, mi_open()
2009
does not assign a get_status() function. In this case the local
2010
("current") status is never updated. We would wrongly think that
2011
we cannot cache the statement.
2013
uint64_t actual_data_file_length;
2014
uint64_t current_data_file_length;
2017
POSIX visibility rules specify that "2. Whatever memory values a
2018
thread can see when it unlocks a mutex <...> can also be seen by any
2019
thread that later locks the same mutex". In this particular case,
2020
concurrent insert thread had modified the data_file_length in
2021
MYISAM_SHARE before it has unlocked (or even locked)
2022
structure_guard_mutex. So, here we're guaranteed to see at least that
2023
value after we've locked the same mutex. We can see a later value
2024
(modified by some other thread) though, but it's ok, as we only want
2025
to know if the variable was changed, the actual new value doesn't matter
2027
actual_data_file_length= file->s->state.state.data_file_length;
2028
current_data_file_length= file->save_state.data_file_length;
2030
if (current_data_file_length != actual_data_file_length)
2032
/* Don't cache current statement. */
2037
/* It is ok to try to cache current statement. */