14
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
19
#include "drizzled/internal/my_bit.h"
20
#include "myisampack.h"
17
#ifdef USE_PRAGMA_IMPLEMENTATION
18
#pragma implementation // gcc: Class implementation
21
#define DRIZZLE_SERVER 1
23
#include <drizzled/server_includes.h>
24
#include <mysys/my_bit.h>
25
#include <myisampack.h>
21
26
#include "ha_myisam.h"
22
#include "myisam_priv.h"
23
#include "drizzled/internal/my_bit.h"
24
#include "drizzled/internal/m_string.h"
25
#include "drizzled/util/test.h"
26
#include "drizzled/error.h"
27
#include "drizzled/errmsg_print.h"
28
#include "drizzled/gettext.h"
29
#include "drizzled/session.h"
30
#include "drizzled/plugin/client.h"
31
#include "drizzled/table.h"
32
#include "drizzled/field/timestamp.h"
33
#include "drizzled/memory/multi_malloc.h"
42
static const string engine_name("MyISAM");
44
pthread_mutex_t THR_LOCK_myisam= PTHREAD_MUTEX_INITIALIZER;
46
static uint32_t repair_threads;
47
static uint32_t block_size;
48
static uint64_t max_sort_file_size;
49
static uint64_t sort_buffer_size;
27
#include "myisamdef.h"
28
#include <drizzled/drizzled_error_messages.h>
30
ulong myisam_recover_options= HA_RECOVER_NONE;
32
/* bits in myisam_recover_options */
33
const char *myisam_recover_names[] =
34
{ "DEFAULT", "BACKUP", "FORCE", "QUICK", NullS};
35
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
36
myisam_recover_names, NULL};
38
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
39
"nulls_ignored", NullS};
40
TYPELIB myisam_stats_method_typelib= {
41
array_elements(myisam_stats_method_names) - 1, "",
42
myisam_stats_method_names, NULL};
51
45
/*****************************************************************************
53
47
*****************************************************************************/
55
static const char *ha_myisam_exts[] = {
61
class MyisamEngine : public drizzled::plugin::StorageEngine
64
MyisamEngine(string name_arg)
65
: drizzled::plugin::StorageEngine(name_arg,
66
HTON_HAS_DATA_DICTIONARY |
67
HTON_CAN_INDEX_BLOBS |
68
HTON_STATS_RECORDS_IS_EXACT |
75
HTON_NEED_READ_RANGE_BUFFER |
76
HTON_SKIP_STORE_LOCK |
82
virtual Cursor *create(TableShare &table,
83
drizzled::memory::Root *mem_root)
85
return new (mem_root) ha_myisam(*this, table);
88
const char **bas_ext() const {
89
return ha_myisam_exts;
92
int doCreateTable(Session *, const char *table_name,
94
drizzled::message::Table&);
96
int doRenameTable(Session*, const char *from, const char *to);
98
int doDropTable(Session&, const string table_name);
100
int doGetTableDefinition(Session& session,
103
const char *table_name,
105
drizzled::message::Table *table_proto);
107
/* Temp only engine, so do not return values. */
108
void doGetTableNames(drizzled::CachedDirectory &, string& , set<string>&) { };
110
uint32_t max_supported_keys() const { return MI_MAX_KEY; }
111
uint32_t max_supported_key_length() const { return MI_MAX_KEY_LENGTH; }
112
uint32_t max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
114
uint32_t index_flags(enum ha_key_alg) const
116
return (HA_READ_NEXT |
124
int MyisamEngine::doGetTableDefinition(Session&,
129
drizzled::message::Table *table_proto)
132
ProtoCache::iterator iter;
134
pthread_mutex_lock(&proto_cache_mutex);
135
iter= proto_cache.find(path);
137
if (iter!= proto_cache.end())
140
table_proto->CopyFrom(((*iter).second));
143
pthread_mutex_unlock(&proto_cache_mutex);
49
static handler *myisam_create_handler(handlerton *hton,
53
return new (mem_root) ha_myisam(hton, table);
149
Convert to push_Warnings if you ever care about this, otherwise, it is a no-op.
56
// collect errors printed by mi_check routines
152
static void mi_check_print_msg(MI_CHECK *, const char* ,
153
const char *, va_list )
58
static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
59
const char *fmt, va_list args)
61
THD* thd = (THD*)param->thd;
62
Protocol *protocol= thd->protocol;
63
uint length, msg_length;
64
char msgbuf[MI_MAX_MSG_BUF];
65
char name[NAME_LEN*2+2];
67
msg_length= vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
68
msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
72
sql_print_error(msgbuf);
76
if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
79
my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
82
length=(uint) (strxmov(name, param->db_name,".",param->table_name,NullS) -
85
TODO: switch from protocol to push_warning here. The main reason we didn't
86
it yet is parallel repair. Due to following trace:
87
mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
89
Also we likely need to lock mutex here (in both cases with protocol and
92
protocol->prepare_for_resend();
93
protocol->store(name, length, system_charset_info);
94
protocol->store(param->op_name, system_charset_info);
95
protocol->store(msg_type, system_charset_info);
96
protocol->store(msgbuf, msg_length, system_charset_info);
97
if (protocol->write())
98
sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
159
Convert Table object to MyISAM key and column definition
105
Convert TABLE object to MyISAM key and column definition
163
table_arg in Table object.
109
table_arg in TABLE object.
164
110
keydef_out out MyISAM key definition.
165
111
recinfo_out out MyISAM column definition.
166
112
records_out out Number of fields.
182
static int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
183
MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
128
int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
129
MI_COLUMNDEF **recinfo_out, uint *records_out)
185
uint32_t i, j, recpos, minpos, fieldpos, temp_length, length;
131
uint i, j, recpos, minpos, fieldpos, temp_length, length;
186
132
enum ha_base_keytype type= HA_KEYTYPE_BINARY;
187
unsigned char *record;
189
135
MI_KEYDEF *keydef;
190
136
MI_COLUMNDEF *recinfo, *recinfo_pos;
191
137
HA_KEYSEG *keyseg;
192
TableShare *share= table_arg->s;
193
uint32_t options= share->db_options_in_use;
194
if (!(drizzled::memory::multi_malloc(false,
138
TABLE_SHARE *share= table_arg->s;
139
uint options= share->db_options_in_use;
140
if (!(my_multi_malloc(MYF(MY_WME),
195
141
recinfo_out, (share->fields * 2 + 2) * sizeof(MI_COLUMNDEF),
196
142
keydef_out, share->keys * sizeof(MI_KEYDEF),
197
&keyseg, (share->key_parts + share->keys) * sizeof(HA_KEYSEG),
199
return(HA_ERR_OUT_OF_MEM);
144
(share->key_parts + share->keys) * sizeof(HA_KEYSEG),
146
return(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
200
147
keydef= *keydef_out;
201
148
recinfo= *recinfo_out;
202
149
pos= table_arg->key_info;
499
442
void _mi_report_crashed(MI_INFO *file, const char *message,
500
const char *sfile, uint32_t sline)
443
const char *sfile, uint sline)
502
Session *cur_session;
503
447
pthread_mutex_lock(&file->s->intern_lock);
504
if ((cur_session= file->in_use))
505
errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from thread_id=%"PRIu64", %s:%d"),
506
cur_session->thread_id,
448
if ((cur_thd= (THD*) file->in_use.data))
449
sql_print_error("Got an error from thread_id=%lu, %s:%d", cur_thd->thread_id,
509
errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from unknown thread, %s:%d"), sfile, sline);
452
sql_print_error("Got an error from unknown thread, %s:%d", sfile, sline);
511
errmsg_printf(ERRMSG_LVL_ERROR, "%s", message);
512
list<Session *>::iterator it= file->s->in_use->begin();
513
while (it != file->s->in_use->end())
454
sql_print_error("%s", message);
455
for (element= file->s->in_use; element; element= list_rest(element))
515
errmsg_printf(ERRMSG_LVL_ERROR, "%s", _("Unknown thread accessing table"));
457
sql_print_error("%s", "Unknown thread accessing table");
518
459
pthread_mutex_unlock(&file->s->intern_lock);
523
ha_myisam::ha_myisam(drizzled::plugin::StorageEngine &engine_arg,
524
TableShare &table_arg)
525
: Cursor(engine_arg, table_arg),
527
can_enable_indexes(true),
464
ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
465
:handler(hton, table_arg), file(0),
466
int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
467
HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
468
HA_DUPLICATE_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
469
HA_FILE_BASED | HA_CAN_GEOMETRY | HA_NO_TRANSACTIONS |
470
HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD | HA_CAN_RTREEKEYS |
471
HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT |
472
HA_NEED_READ_RANGE_BUFFER | HA_MRR_CANT_SORT),
473
can_enable_indexes(1)
531
Cursor *ha_myisam::clone(drizzled::memory::Root *mem_root)
476
handler *ha_myisam::clone(MEM_ROOT *mem_root)
533
ha_myisam *new_handler= static_cast <ha_myisam *>(Cursor::clone(mem_root));
478
ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(mem_root));
535
480
new_handler->file->state= file->state;
536
481
return new_handler;
539
const char *ha_myisam::index_type(uint32_t )
485
static const char *ha_myisam_exts[] = {
491
const char **ha_myisam::bas_ext() const
493
return ha_myisam_exts;
497
const char *ha_myisam::index_type(uint key_number __attribute__((unused)))
544
502
/* Name is here without an extension */
545
int ha_myisam::open(const char *name, int mode, uint32_t test_if_locked)
503
int ha_myisam::open(const char *name, int mode, uint test_if_locked)
547
505
MI_KEYDEF *keyinfo;
548
506
MI_COLUMNDEF *recinfo= 0;
553
511
If the user wants to have memory mapped data files, add an
564
522
open of a table that is in use by other threads already (if the
565
523
MyISAM share exists already).
567
if (!(file=mi_open(name, mode, test_if_locked)))
568
return (errno ? errno : -1);
525
if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
526
return (my_errno ? my_errno : -1);
570
527
if (!table->s->tmp_table) /* No need to perform a check for tmp table */
572
if ((errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
529
if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
531
/* purecov: begin inspected */
576
535
if (check_definition(keyinfo, recinfo, table->s->keys, recs,
577
536
file->s->keyinfo, file->s->rec,
578
537
file->s->base.keys, file->s->base.fields, true))
580
errno= HA_ERR_CRASHED;
539
/* purecov: begin inspected */
540
my_errno= HA_ERR_CRASHED;
585
546
if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
586
mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0);
547
VOID(mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0));
588
549
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
589
550
if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
590
mi_extra(file, HA_EXTRA_WAIT_LOCK, 0);
551
VOID(mi_extra(file, HA_EXTRA_WAIT_LOCK, 0));
591
552
if (!table->s->db_record_offset)
595
keys_with_parts.reset();
553
int_table_flags|=HA_REC_NOT_IN_SEQ;
554
if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
555
int_table_flags|=HA_HAS_CHECKSUM;
557
keys_with_parts.clear_all();
596
558
for (i= 0; i < table->s->keys; i++)
598
560
table->key_info[i].block_size= file->s->keyinfo[i].block_length;
646
612
return mi_write(file,buf);
650
int ha_myisam::repair(Session *session, MI_CHECK ¶m, bool do_optimize)
653
uint32_t local_testflag= param.testflag;
615
int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
617
if (!file) return HA_ADMIN_INTERNAL_ERROR;
620
MYISAM_SHARE* share = file->s;
621
const char *old_proc_info=thd->proc_info;
623
thd_proc_info(thd, "Checking table");
624
myisamchk_init(¶m);
626
param.op_name = "check";
627
param.db_name= table->s->db.str;
628
param.table_name= table->alias;
629
param.testflag = check_opt->flags | T_CHECK | T_SILENT;
630
param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
632
if (!(table->db_stat & HA_READ_ONLY))
633
param.testflag|= T_STATISTICS;
634
param.using_global_keycache = 1;
636
if (!mi_is_crashed(file) &&
637
(((param.testflag & T_CHECK_ONLY_CHANGED) &&
638
!(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
639
STATE_CRASHED_ON_REPAIR)) &&
640
share->state.open_count == 0) ||
641
((param.testflag & T_FAST) && (share->state.open_count ==
642
(uint) (share->global_changed ? 1 : 0)))))
643
return HA_ADMIN_ALREADY_DONE;
645
error = chk_status(¶m, file); // Not fatal
646
error = chk_size(¶m, file);
648
error |= chk_del(¶m, file, param.testflag);
650
error = chk_key(¶m, file);
653
if ((!(param.testflag & T_QUICK) &&
655
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
656
(param.testflag & (T_EXTEND | T_MEDIUM)))) ||
659
uint old_testflag=param.testflag;
660
param.testflag|=T_MEDIUM;
661
if (!(error= init_io_cache(¶m.read_cache, file->dfile,
662
my_default_record_cache_size, READ_CACHE,
663
share->pack.header_length, 1, MYF(MY_WME))))
665
error= chk_data_link(¶m, file, param.testflag & T_EXTEND);
666
end_io_cache(&(param.read_cache));
668
param.testflag= old_testflag;
673
if ((share->state.changed & (STATE_CHANGED |
674
STATE_CRASHED_ON_REPAIR |
675
STATE_CRASHED | STATE_NOT_ANALYZED)) ||
676
(param.testflag & T_STATISTICS) ||
679
file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
680
pthread_mutex_lock(&share->intern_lock);
681
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
682
STATE_CRASHED_ON_REPAIR);
683
if (!(table->db_stat & HA_READ_ONLY))
684
error=update_state_info(¶m,file,UPDATE_TIME | UPDATE_OPEN_COUNT |
686
pthread_mutex_unlock(&share->intern_lock);
687
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
691
else if (!mi_is_crashed(file) && !thd->killed)
693
mi_mark_crashed(file);
694
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
697
thd_proc_info(thd, old_proc_info);
698
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
703
analyze the key distribution in the table
704
As the table may be only locked for read, we have to take into account that
705
two threads may do an analyze at the same time!
708
int ha_myisam::analyze(THD *thd,
709
HA_CHECK_OPT* check_opt __attribute__((unused)))
713
MYISAM_SHARE* share = file->s;
715
myisamchk_init(¶m);
717
param.op_name= "analyze";
718
param.db_name= table->s->db.str;
719
param.table_name= table->alias;
720
param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
721
T_DONT_CHECK_CHECKSUM);
722
param.using_global_keycache = 1;
723
param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
725
if (!(share->state.changed & STATE_NOT_ANALYZED))
726
return HA_ADMIN_ALREADY_DONE;
728
error = chk_key(¶m, file);
731
pthread_mutex_lock(&share->intern_lock);
732
error=update_state_info(¶m,file,UPDATE_STAT);
733
pthread_mutex_unlock(&share->intern_lock);
735
else if (!mi_is_crashed(file) && !thd->killed)
736
mi_mark_crashed(file);
737
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
741
int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
745
ha_rows start_records;
747
if (!file) return HA_ADMIN_INTERNAL_ERROR;
749
myisamchk_init(¶m);
751
param.op_name= "repair";
752
param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
753
T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
754
(check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
755
param.sort_buffer_length= check_opt->sort_buffer_size;
756
start_records=file->state->records;
757
while ((error=repair(thd,param,0)) && param.retry_repair)
759
param.retry_repair=0;
760
if (test_all_bits(param.testflag,
761
(uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
763
param.testflag&= ~T_RETRY_WITHOUT_QUICK;
764
sql_print_information("Retrying repair of: '%s' without quick",
768
param.testflag&= ~T_QUICK;
769
if ((param.testflag & T_REP_BY_SORT))
771
param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
772
sql_print_information("Retrying repair of: '%s' with keycache",
778
if (!error && start_records != file->state->records &&
779
!(check_opt->flags & T_VERY_SILENT))
781
char llbuff[22],llbuff2[22];
782
sql_print_information("Found %s of %s rows when repairing '%s'",
783
llstr(file->state->records, llbuff),
784
llstr(start_records, llbuff2),
790
int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
793
if (!file) return HA_ADMIN_INTERNAL_ERROR;
796
myisamchk_init(¶m);
798
param.op_name= "optimize";
799
param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
800
T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
801
param.sort_buffer_length= check_opt->sort_buffer_size;
802
if ((error= repair(thd,param,1)) && param.retry_repair)
804
sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying",
805
my_errno, param.db_name, param.table_name);
806
param.testflag&= ~T_REP_BY_SORT;
807
error= repair(thd,param,1);
813
int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_optimize)
816
uint local_testflag=param.testflag;
654
817
bool optimize_done= !do_optimize, statistics_done=0;
655
const char *old_proc_info= session->get_proc_info();
818
const char *old_proc_info=thd->proc_info;
656
819
char fixed_name[FN_REFLEN];
657
820
MYISAM_SHARE* share = file->s;
658
821
ha_rows rows= file->state->records;
697
861
uint64_t key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
698
862
mi_get_mask_all_keys_active(share->base.keys) :
699
863
share->state.key_map);
700
uint32_t testflag=param.testflag;
864
uint testflag=param.testflag;
701
865
if (mi_test_if_sort_rep(file,file->state->records,key_map,0) &&
702
866
(local_testflag & T_REP_BY_SORT))
704
868
local_testflag|= T_STATISTICS;
705
869
param.testflag|= T_STATISTICS; // We get this for free
706
870
statistics_done=1;
707
if (repair_threads > 1)
871
if (thd->variables.myisam_repair_threads>1)
710
874
/* TODO: respect myisam_repair_threads variable */
711
875
snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
712
session->set_proc_info(buf);
876
thd_proc_info(thd, buf);
713
877
error = mi_repair_parallel(¶m, file, fixed_name,
714
878
param.testflag & T_QUICK);
715
session->set_proc_info("Repair done"); // to reset proc_info, as
879
thd_proc_info(thd, "Repair done"); // to reset proc_info, as
716
880
// it was pointing to local buffer
720
session->set_proc_info("Repair by sorting");
884
thd_proc_info(thd, "Repair by sorting");
721
885
error = mi_repair_by_sort(¶m, file, fixed_name,
722
886
param.testflag & T_QUICK);
727
session->set_proc_info("Repair with keycache");
891
thd_proc_info(thd, "Repair with keycache");
728
892
param.testflag &= ~T_REP_BY_SORT;
729
893
error= mi_repair(¶m, file, fixed_name,
730
894
param.testflag & T_QUICK);
791
955
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
792
956
update_state_info(¶m, file, 0);
794
session->set_proc_info(old_proc_info);
795
mi_lock_database(file,F_UNLCK);
958
thd_proc_info(thd, old_proc_info);
959
if (!thd->locked_tables)
960
mi_lock_database(file,F_UNLCK);
797
961
return(error ? HA_ADMIN_FAILED :
798
962
!optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
967
Assign table indexes to a specific key cache.
970
int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
972
KEY_CACHE *new_key_cache= check_opt->key_cache;
973
const char *errmsg= 0;
974
int error= HA_ADMIN_OK;
976
TABLE_LIST *table_list= table->pos_in_table_list;
978
table->keys_in_use_for_query.clear_all();
980
if (table_list->process_index_hints(table))
981
return(HA_ADMIN_FAILED);
983
if (!table->keys_in_use_for_query.is_clear_all())
984
/* use all keys if there's no list specified by the user through hints */
985
map= table->keys_in_use_for_query.to_uint64_t();
987
if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
989
char buf[STRING_BUFFER_USUAL_SIZE];
990
snprintf(buf, sizeof(buf),
991
"Failed to flush to index file (errno: %d)", error);
993
error= HA_ADMIN_CORRUPT;
996
if (error != HA_ADMIN_OK)
998
/* Send error to user */
1000
myisamchk_init(¶m);
1002
param.op_name= "assign_to_keycache";
1003
param.db_name= table->s->db.str;
1004
param.table_name= table->s->table_name.str;
1006
mi_check_print_error(¶m, errmsg);
803
1013
Disable indexes, making it persistent if requested.
893
1103
else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
895
Session *session=current_session;
1105
THD *thd=current_thd;
897
const char *save_proc_info= session->get_proc_info();
898
session->set_proc_info("Creating index");
1107
const char *save_proc_info=thd->proc_info;
1108
thd_proc_info(thd, "Creating index");
899
1109
myisamchk_init(¶m);
900
1110
param.op_name= "recreating_index";
901
1111
param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
902
1112
T_CREATE_MISSING_KEYS);
903
1113
param.myf_rw&= ~MY_WAIT_IF_FULL;
904
param.sort_buffer_length= (size_t)sort_buffer_size;
905
param.stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
906
if ((error= (repair(session,param,0) != HA_ADMIN_OK)) && param.retry_repair)
1114
param.sort_buffer_length= thd->variables.myisam_sort_buff_size;
1115
param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
1116
param.tmpdir=&mysql_tmpdir_list;
1117
if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair)
908
errmsg_printf(ERRMSG_LVL_WARN, "Warning: Enabling keys got errno %d on %s.%s, retrying",
909
errno, param.db_name, param.table_name);
1119
sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, retrying",
1120
my_errno, param.db_name, param.table_name);
910
1121
/* Repairing by sort failed. Now try standard repair method. */
911
1122
param.testflag&= ~(T_REP_BY_SORT | T_QUICK);
912
error= (repair(session,param,0) != HA_ADMIN_OK);
1123
error= (repair(thd,param,0) != HA_ADMIN_OK);
914
1125
If the standard repair succeeded, clear all error messages which
915
1126
might have been set by the first repair. They can still be seen
916
1127
with SHOW WARNINGS then.
919
session->clear_error();
921
1132
info(HA_STATUS_CONST);
922
session->set_proc_info(save_proc_info);
1133
thd_proc_info(thd, save_proc_info);
1023
int ha_myisam::update_row(const unsigned char *old_data, unsigned char *new_data)
1236
bool ha_myisam::check_and_repair(THD *thd)
1241
uint old_query_length;
1242
HA_CHECK_OPT check_opt;
1245
check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
1246
// Don't use quick if deleted rows
1247
if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
1248
check_opt.flags|=T_QUICK;
1249
sql_print_warning("Checking table: '%s'",table->s->path.str);
1251
old_query= thd->query;
1252
old_query_length= thd->query_length;
1253
pthread_mutex_lock(&LOCK_thread_count);
1254
thd->query= table->s->table_name.str;
1255
thd->query_length= table->s->table_name.length;
1256
pthread_mutex_unlock(&LOCK_thread_count);
1258
if ((marked_crashed= mi_is_crashed(file)) || check(thd, &check_opt))
1260
sql_print_warning("Recovering table: '%s'",table->s->path.str);
1262
((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
1263
(marked_crashed ? 0 : T_QUICK) |
1264
(myisam_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
1266
if (repair(thd, &check_opt))
1269
pthread_mutex_lock(&LOCK_thread_count);
1270
thd->query= old_query;
1271
thd->query_length= old_query_length;
1272
pthread_mutex_unlock(&LOCK_thread_count);
1276
bool ha_myisam::is_crashed() const
1278
return (file->s->state.changed & STATE_CRASHED ||
1279
(file->s->state.open_count));
1282
int ha_myisam::update_row(const uchar *old_data, uchar *new_data)
1025
1284
ha_statistic_increment(&SSV::ha_update_count);
1026
1285
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
1028
1287
return mi_update(file,old_data,new_data);
1031
int ha_myisam::delete_row(const unsigned char *buf)
1290
int ha_myisam::delete_row(const uchar *buf)
1033
1292
ha_statistic_increment(&SSV::ha_delete_count);
1034
1293
return mi_delete(file,buf);
1038
int ha_myisam::index_init(uint32_t idx, bool )
1298
bool index_cond_func_myisam(void *arg)
1300
ha_myisam *h= (ha_myisam*)arg;
1301
/*if (h->in_range_read)*/
1304
if (h->compare_key2(h->end_range) > 0)
1305
return 2; /* caller should return HA_ERR_END_OF_FILE already */
1307
return (bool)h->pushed_idx_cond->val_int();
1313
int ha_myisam::index_init(uint idx, bool sorted __attribute__((unused)))
1040
1315
active_index=idx;
1041
1316
//in_range_read= false;
1317
if (pushed_idx_cond_keyno == idx)
1318
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1046
1323
int ha_myisam::index_end()
1048
1325
active_index=MAX_KEY;
1326
//pushed_idx_cond_keyno= MAX_KEY;
1327
mi_set_index_cond_func(file, NULL, 0);
1328
in_range_check_pushed_down= false;
1329
ds_mrr.dsmrr_close();
1053
int ha_myisam::index_read_map(unsigned char *buf, const unsigned char *key,
1334
int ha_myisam::index_read_map(uchar *buf, const uchar *key,
1054
1335
key_part_map keypart_map,
1055
1336
enum ha_rkey_function find_flag)
1213
1494
if (flag & HA_STATUS_CONST)
1215
TableShare *share= table->s;
1496
TABLE_SHARE *share= table->s;
1216
1497
stats.max_data_file_length= misam_info.max_data_file_length;
1217
1498
stats.max_index_file_length= misam_info.max_index_file_length;
1218
1499
stats.create_time= misam_info.create_time;
1219
1500
ref_length= misam_info.reflength;
1220
1501
share->db_options_in_use= misam_info.options;
1221
stats.block_size= block_size; /* record block size */
1502
stats.block_size= myisam_block_size; /* record block size */
1223
1504
/* Update share */
1224
1505
if (share->tmp_table == NO_TMP_TABLE)
1225
1506
pthread_mutex_lock(&share->mutex);
1226
set_prefix(share->keys_in_use, share->keys);
1228
* Due to bug 394932 (32-bit solaris build failure), we need
1229
* to convert the uint64_t key_map member of the misam_info
1230
* structure in to a std::bitset so that we can logically and
1231
* it with the share->key_in_use key_map.
1234
string binary_key_map;
1235
uint64_t num= misam_info.key_map;
1237
* Convert the uint64_t to a binary
1238
* string representation of it.
1242
uint64_t bin_digit= num % 2;
1246
binary_key_map.append(ostr.str());
1248
* Now we have the binary string representation of the
1249
* flags, we need to fill that string representation out
1250
* with the appropriate number of bits. This is needed
1251
* since key_map is declared as a std::bitset of a certain bit
1252
* width that depends on the MAX_INDEXES variable.
1254
if (MAX_INDEXES <= 64)
1256
size_t len= 72 - binary_key_map.length();
1257
string all_zeros(len, '0');
1258
binary_key_map.insert(binary_key_map.begin(),
1264
size_t len= (MAX_INDEXES + 7) / 8 * 8;
1265
string all_zeros(len, '0');
1266
binary_key_map.insert(binary_key_map.begin(),
1270
key_map tmp_map(binary_key_map);
1271
share->keys_in_use&= tmp_map;
1272
share->keys_for_keyread&= share->keys_in_use;
1507
share->keys_in_use.set_prefix(share->keys);
1508
share->keys_in_use.intersect_extended(misam_info.key_map);
1509
share->keys_for_keyread.intersect(share->keys_in_use);
1273
1510
share->db_record_offset= misam_info.record_offset;
1274
1511
if (share->key_parts)
1275
1512
memcpy(table->key_info[0].rec_per_key,
1328
1573
return mi_delete_all_rows(file);
1331
int MyisamEngine::doDropTable(Session&, const string table_path)
1576
int ha_myisam::delete_table(const char *name)
1333
ProtoCache::iterator iter;
1335
pthread_mutex_lock(&proto_cache_mutex);
1336
iter= proto_cache.find(table_path.c_str());
1338
if (iter!= proto_cache.end())
1339
proto_cache.erase(iter);
1341
pthread_mutex_unlock(&proto_cache_mutex);
1343
return mi_delete_table(table_path.c_str());
1578
return mi_delete_table(name);
1347
int ha_myisam::external_lock(Session *session, int lock_type)
1582
int ha_myisam::external_lock(THD *thd, int lock_type)
1349
file->in_use= session;
1584
file->in_use.data= thd;
1350
1585
return mi_lock_database(file, !table->s->tmp_table ?
1351
1586
lock_type : ((lock_type == F_UNLCK) ?
1352
1587
F_UNLCK : F_EXTRA_LCK));
1355
int MyisamEngine::doCreateTable(Session *, const char *table_name,
1357
drizzled::message::Table& create_proto)
1590
THR_LOCK_DATA **ha_myisam::store_lock(THD *thd __attribute__((unused)),
1592
enum thr_lock_type lock_type)
1594
if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
1595
file->lock.type=lock_type;
1600
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
1602
ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
1603
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
1605
create_info->auto_increment_value= stats.auto_increment_value;
1607
create_info->data_file_name=data_file_name;
1608
create_info->index_file_name=index_file_name;
1612
int ha_myisam::create(const char *name, register TABLE *table_arg,
1613
HA_CREATE_INFO *ha_create_info)
1360
uint32_t create_flags= 0, create_records;
1616
uint create_flags= 0, records;
1361
1617
char buff[FN_REFLEN];
1362
1618
MI_KEYDEF *keydef;
1363
1619
MI_COLUMNDEF *recinfo;
1364
1620
MI_CREATE_INFO create_info;
1365
TableShare *share= table_arg.s;
1366
uint32_t options= share->db_options_in_use;
1367
if ((error= table2myisam(&table_arg, &keydef, &recinfo, &create_records)))
1621
TABLE_SHARE *share= table_arg->s;
1622
uint options= share->db_options_in_use;
1623
if ((error= table2myisam(table_arg, &keydef, &recinfo, &records)))
1624
return(error); /* purecov: inspected */
1369
1625
memset(&create_info, 0, sizeof(create_info));
1370
create_info.max_rows= create_proto.options().max_rows();
1371
create_info.reloc_rows= create_proto.options().min_rows();
1626
create_info.max_rows= share->max_rows;
1627
create_info.reloc_rows= share->min_rows;
1372
1628
create_info.with_auto_increment= share->next_number_key_offset == 0;
1373
create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
1374
create_proto.options().auto_increment_value() -1 :
1629
create_info.auto_increment= (ha_create_info->auto_increment_value ?
1630
ha_create_info->auto_increment_value -1 :
1376
create_info.data_file_length= (create_proto.options().max_rows() *
1377
create_proto.options().avg_row_length());
1378
create_info.data_file_name= NULL;
1379
create_info.index_file_name= NULL;
1632
create_info.data_file_length= ((uint64_t) share->max_rows *
1633
share->avg_row_length);
1634
create_info.data_file_name= ha_create_info->data_file_name;
1635
create_info.index_file_name= ha_create_info->index_file_name;
1380
1636
create_info.language= share->table_charset->number;
1382
if (create_proto.type() == drizzled::message::Table::TEMPORARY)
1638
if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
1383
1639
create_flags|= HA_CREATE_TMP_TABLE;
1640
if (ha_create_info->options & HA_CREATE_KEEP_FILES)
1641
create_flags|= HA_CREATE_KEEP_FILES;
1384
1642
if (options & HA_OPTION_PACK_RECORD)
1385
1643
create_flags|= HA_PACK_RECORD;
1644
if (options & HA_OPTION_CHECKSUM)
1645
create_flags|= HA_CREATE_CHECKSUM;
1646
if (options & HA_OPTION_DELAY_KEY_WRITE)
1647
create_flags|= HA_CREATE_DELAY_KEY_WRITE;
1387
1649
/* TODO: Check that the following fn_format is really needed */
1388
error= mi_create(fn_format(buff, table_name, "", "",
1650
error= mi_create(fn_format(buff, name, "", "",
1389
1651
MY_UNPACK_FILENAME|MY_APPEND_EXT),
1390
1652
share->keys, keydef,
1391
create_records, recinfo,
1392
1654
0, (MI_UNIQUEDEF*) 0,
1393
1655
&create_info, create_flags);
1394
free((unsigned char*) recinfo);
1396
pthread_mutex_lock(&proto_cache_mutex);
1397
proto_cache.insert(make_pair(table_name, create_proto));
1398
pthread_mutex_unlock(&proto_cache_mutex);
1656
my_free((uchar*) recinfo, MYF(0));
1404
int MyisamEngine::doRenameTable(Session*,
1405
const char *from, const char *to)
1661
int ha_myisam::rename_table(const char * from, const char * to)
1407
1663
return mi_rename(from,to);
1411
void ha_myisam::get_auto_increment(uint64_t ,
1667
void ha_myisam::get_auto_increment(uint64_t offset __attribute__((unused)),
1668
uint64_t increment __attribute__((unused)),
1669
uint64_t nb_desired_values __attribute__((unused)),
1414
1670
uint64_t *first_value,
1415
1671
uint64_t *nb_reserved_values)
1419
unsigned char key[MI_MAX_KEY_LENGTH];
1675
uchar key[MI_MAX_KEY_LENGTH];
1421
1677
if (!table->s->next_number_key_offset)
1422
1678
{ // Autoincrement at key-start
1485
ha_rows ha_myisam::records_in_range(uint32_t inx, key_range *min_key,
1741
ha_rows ha_myisam::records_in_range(uint inx, key_range *min_key,
1486
1742
key_range *max_key)
1488
1744
return (ha_rows) mi_records_in_range(file, (int) inx, min_key, max_key);
1492
uint32_t ha_myisam::checksum() const
1748
uint ha_myisam::checksum() const
1494
1750
return (uint)file->state->checksum;
1497
static MyisamEngine *engine= NULL;
1499
static int myisam_init(drizzled::plugin::Registry ®istry)
1754
bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
1502
engine= new MyisamEngine(engine_name);
1503
registry.add(engine);
1505
pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_FAST);
1507
/* call ha_init_key_cache() on all key caches to init them */
1508
error= init_key_cache(dflt_key_cache,
1509
(uint32_t) dflt_key_cache->param_block_size,
1510
(uint32_t) dflt_key_cache->param_buff_size,
1511
dflt_key_cache->param_division_limit,
1512
dflt_key_cache->param_age_threshold);
1515
exit(1); /* Memory Allocation Failure */
1757
uint options= table->s->db_options_in_use;
1759
if (info->auto_increment_value != stats.auto_increment_value ||
1760
info->data_file_name != data_file_name ||
1761
info->index_file_name != index_file_name ||
1762
table_changes == IS_EQUAL_NO ||
1763
table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
1764
return COMPATIBLE_DATA_NO;
1766
if ((options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1767
HA_OPTION_DELAY_KEY_WRITE)) !=
1768
(info->table_options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1769
HA_OPTION_DELAY_KEY_WRITE)))
1770
return COMPATIBLE_DATA_NO;
1771
return COMPATIBLE_DATA_YES;
1520
static int myisam_deinit(drizzled::plugin::Registry ®istry)
1774
int myisam_deinit(void *hton __attribute__((unused)))
1522
registry.remove(engine);
1525
pthread_mutex_destroy(&THR_LOCK_myisam);
1526
end_key_cache(dflt_key_cache, 1); // Can never fail
1528
1776
return mi_panic(HA_PANIC_CLOSE);
1531
static DRIZZLE_SYSVAR_UINT(block_size, block_size,
1532
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1533
N_("Block size to be used for MyISAM index pages."),
1534
NULL, NULL, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
1535
MI_MAX_KEY_BLOCK_LENGTH, 0);
1537
static DRIZZLE_SYSVAR_UINT(repair_threads, repair_threads,
1538
PLUGIN_VAR_RQCMDARG,
1539
N_("Number of threads to use when repairing MyISAM tables. The value of "
1540
"1 disables parallel repair."),
1541
NULL, NULL, 1, 1, UINT32_MAX, 0);
1543
static DRIZZLE_SYSVAR_ULONGLONG(max_sort_file_size, max_sort_file_size,
1544
PLUGIN_VAR_RQCMDARG,
1545
N_("Don't use the fast sort index method to created index if the temporary file would get bigger than this."),
1546
NULL, NULL, INT32_MAX, 0, UINT64_MAX, 0);
1548
static DRIZZLE_SYSVAR_ULONGLONG(sort_buffer_size, sort_buffer_size,
1549
PLUGIN_VAR_RQCMDARG,
1550
N_("The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE."),
1551
NULL, NULL, 8192*1024, 1024, SIZE_MAX, 0);
1553
extern uint32_t data_pointer_size;
1554
static DRIZZLE_SYSVAR_UINT(data_pointer_size, data_pointer_size,
1555
PLUGIN_VAR_RQCMDARG,
1556
N_("Default pointer size to be used for MyISAM tables."),
1557
NULL, NULL, 6, 2, 7, 0);
1559
static drizzle_sys_var* system_variables[]= {
1560
DRIZZLE_SYSVAR(block_size),
1561
DRIZZLE_SYSVAR(repair_threads),
1562
DRIZZLE_SYSVAR(max_sort_file_size),
1563
DRIZZLE_SYSVAR(sort_buffer_size),
1564
DRIZZLE_SYSVAR(data_pointer_size),
1569
DRIZZLE_DECLARE_PLUGIN
1779
static int myisam_init(void *p)
1781
handlerton *myisam_hton;
1783
myisam_hton= (handlerton *)p;
1784
myisam_hton->state= SHOW_OPTION_YES;
1785
myisam_hton->db_type= DB_TYPE_MYISAM;
1786
myisam_hton->create= myisam_create_handler;
1787
myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
1793
/****************************************************************************
1794
* MyISAM MRR implementation: use DS-MRR
1795
***************************************************************************/
1797
int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
1798
uint n_ranges, uint mode,
1799
HANDLER_BUFFER *buf)
1801
return ds_mrr.dsmrr_init(this, &table->key_info[active_index],
1802
seq, seq_init_param, n_ranges, mode, buf);
1805
int ha_myisam::multi_range_read_next(char **range_info)
1807
return ds_mrr.dsmrr_next(this, range_info);
1810
ha_rows ha_myisam::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
1811
void *seq_init_param,
1812
uint n_ranges, uint *bufsz,
1813
uint *flags, COST_VECT *cost)
1816
This call is here because there is no location where this->table would
1818
TODO: consider moving it into some per-query initialization call.
1820
ds_mrr.init(this, table);
1821
return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz,
1825
int ha_myisam::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
1826
uint *bufsz, uint *flags, COST_VECT *cost)
1828
ds_mrr.init(this, table);
1829
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
1832
/* MyISAM MRR implementation ends */
1835
/* Index condition pushdown implementation*/
1838
Item *ha_myisam::idx_cond_push(uint keyno_arg, Item* idx_cond_arg)
1840
pushed_idx_cond_keyno= keyno_arg;
1841
pushed_idx_cond= idx_cond_arg;
1842
in_range_check_pushed_down= true;
1843
if (active_index == pushed_idx_cond_keyno)
1844
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1849
mysql_declare_plugin(myisam)
1851
DRIZZLE_STORAGE_ENGINE_PLUGIN,