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 */
18
#define DRIZZLE_SERVER 1
20
#include <drizzled/server_includes.h>
21
#include <mysys/my_bit.h>
22
#include <myisampack.h>
21
23
#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>
24
#include "myisamdef.h"
26
25
#include <drizzled/util/test.h>
27
26
#include <drizzled/error.h>
28
#include <drizzled/errmsg_print.h>
29
27
#include <drizzled/gettext.h>
30
28
#include <drizzled/session.h>
31
#include <drizzled/plugin.h>
32
#include <drizzled/plugin/client.h>
29
#include <drizzled/protocol.h>
33
30
#include <drizzled/table.h>
34
#include <drizzled/memory/multi_malloc.h>
35
#include <drizzled/plugin/daemon.h>
37
#include <drizzled/plugin/storage_engine.h>
39
#include <boost/algorithm/string.hpp>
40
#include <boost/scoped_ptr.hpp>
47
#include <boost/program_options.hpp>
48
#include <drizzled/module/option_map.h>
50
namespace po= boost::program_options;
53
using namespace drizzled;
55
static const string engine_name("MyISAM");
57
boost::mutex THR_LOCK_myisam;
59
static uint32_t myisam_key_cache_block_size= KEY_CACHE_BLOCK_SIZE;
60
static uint32_t myisam_key_cache_size;
61
static uint32_t myisam_key_cache_division_limit;
62
static uint32_t myisam_key_cache_age_threshold;
63
static uint64_t max_sort_file_size;
64
typedef constrained_check<size_t, SIZE_MAX, 1024, 1024> sort_buffer_constraint;
65
static sort_buffer_constraint sort_buffer_size;
67
void st_mi_isam_share::setKeyCache()
69
(void)init_key_cache(&key_cache,
70
myisam_key_cache_block_size,
71
myisam_key_cache_size,
72
myisam_key_cache_division_limit,
73
myisam_key_cache_age_threshold);
31
#include <drizzled/field/timestamp.h>
33
ulong myisam_recover_options= HA_RECOVER_NONE;
34
pthread_mutex_t THR_LOCK_myisam= PTHREAD_MUTEX_INITIALIZER;
36
/* bits in myisam_recover_options */
37
const char *myisam_recover_names[] =
38
{ "DEFAULT", "BACKUP", "FORCE", "QUICK", NULL};
39
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
40
myisam_recover_names, NULL};
42
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
43
"nulls_ignored", NULL};
44
TYPELIB myisam_stats_method_typelib= {
45
array_elements(myisam_stats_method_names) - 1, "",
46
myisam_stats_method_names, NULL};
76
49
/*****************************************************************************
78
51
*****************************************************************************/
80
static const char *ha_myisam_exts[] = {
86
class MyisamEngine : public plugin::StorageEngine
89
MyisamEngine(const MyisamEngine&);
90
MyisamEngine& operator=(const MyisamEngine&);
92
explicit MyisamEngine(string name_arg) :
93
plugin::StorageEngine(name_arg,
94
HTON_CAN_INDEX_BLOBS |
95
HTON_STATS_RECORDS_IS_EXACT |
101
HTON_SKIP_STORE_LOCK)
105
virtual ~MyisamEngine()
107
mi_panic(HA_PANIC_CLOSE);
110
virtual Cursor *create(Table &table)
112
return new ha_myisam(*this, table);
115
const char **bas_ext() const {
116
return ha_myisam_exts;
119
int doCreateTable(Session&,
121
const identifier::Table &identifier,
124
int doRenameTable(Session&, const identifier::Table &from, const identifier::Table &to);
126
int doDropTable(Session&, const identifier::Table &identifier);
128
int doGetTableDefinition(Session& session,
129
const identifier::Table &identifier,
130
message::Table &table_message);
132
uint32_t max_supported_keys() const { return MI_MAX_KEY; }
133
uint32_t max_supported_key_length() const { return MI_MAX_KEY_LENGTH; }
134
uint32_t max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
136
uint32_t index_flags(enum ha_key_alg) const
138
return (HA_READ_NEXT |
144
bool doDoesTableExist(Session& session, const identifier::Table &identifier);
146
void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
147
const drizzled::identifier::Schema &schema_identifier,
148
drizzled::identifier::Table::vector &set_of_identifiers);
149
bool validateCreateTableOption(const std::string &key, const std::string &state)
152
if (boost::iequals(key, "ROW_FORMAT"))
161
void MyisamEngine::doGetTableIdentifiers(drizzled::CachedDirectory&,
162
const drizzled::identifier::Schema&,
163
drizzled::identifier::Table::vector&)
167
bool MyisamEngine::doDoesTableExist(Session &session, const identifier::Table &identifier)
169
return session.getMessageCache().doesTableMessageExist(identifier);
172
int MyisamEngine::doGetTableDefinition(Session &session,
173
const identifier::Table &identifier,
174
message::Table &table_message)
176
if (session.getMessageCache().getTableMessage(identifier, table_message))
182
Convert to push_Warnings if you ever care about this, otherwise, it is a no-op.
185
static void mi_check_print_msg(MI_CHECK *, const char* ,
186
const char *, va_list )
53
static handler *myisam_create_handler(handlerton *hton,
57
return new (mem_root) ha_myisam(hton, table);
60
// collect errors printed by mi_check routines
62
static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
63
const char *fmt, va_list args)
65
Session* session = (Session*)param->session;
66
Protocol *protocol= session->protocol;
67
uint32_t length, msg_length;
68
char msgbuf[MI_MAX_MSG_BUF];
69
char name[NAME_LEN*2+2];
71
msg_length= vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
72
msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
74
if (!session->vio_ok())
76
sql_print_error("%s",msgbuf);
80
if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
83
my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
86
length=(uint) (strxmov(name, param->db_name,".",param->table_name,NULL) -
89
TODO: switch from protocol to push_warning here. The main reason we didn't
90
it yet is parallel repair. Due to following trace:
91
mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
93
Also we likely need to lock mutex here (in both cases with protocol and
96
protocol->prepare_for_resend();
97
protocol->store(name, length, system_charset_info);
98
protocol->store(param->op_name, system_charset_info);
99
protocol->store(msg_type, system_charset_info);
100
protocol->store(msgbuf, msg_length, system_charset_info);
101
if (protocol->write())
102
sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
215
static int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
216
MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
132
int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
133
MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
218
135
uint32_t i, j, recpos, minpos, fieldpos, temp_length, length;
219
136
enum ha_base_keytype type= HA_KEYTYPE_BINARY;
220
137
unsigned char *record;
221
139
MI_KEYDEF *keydef;
222
140
MI_COLUMNDEF *recinfo, *recinfo_pos;
223
141
HA_KEYSEG *keyseg;
224
TableShare *share= table_arg->getMutableShare();
142
TABLE_SHARE *share= table_arg->s;
225
143
uint32_t options= share->db_options_in_use;
226
if (!(memory::multi_malloc(false,
227
recinfo_out, (share->sizeFields() * 2 + 2) * sizeof(MI_COLUMNDEF),
228
keydef_out, share->sizeKeys() * sizeof(MI_KEYDEF),
229
&keyseg, (share->key_parts + share->sizeKeys()) * sizeof(HA_KEYSEG),
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),
231
return(HA_ERR_OUT_OF_MEM);
150
return(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
232
151
keydef= *keydef_out;
233
152
recinfo= *recinfo_out;
234
for (i= 0; i < share->sizeKeys(); i++)
153
pos= table_arg->key_info;
154
for (i= 0; i < share->keys; i++, pos++)
236
KeyInfo *pos= &table_arg->key_info[i];
237
156
keydef[i].flag= ((uint16_t) pos->flags & (HA_NOSAME));
238
157
keydef[i].key_alg= HA_KEY_ALG_BTREE;
239
158
keydef[i].block_length= pos->block_size;
532
447
const char *sfile, uint32_t sline)
534
449
Session *cur_session;
535
if ((cur_session= file->in_use))
537
errmsg_printf(error::ERROR, _("Got an error from thread_id=%"PRIu64", %s:%d"),
451
pthread_mutex_lock(&file->s->intern_lock);
452
if ((cur_session= (Session*) file->in_use.data))
453
sql_print_error(_("Got an error from thread_id=%"PRIu64", %s:%d"),
538
454
cur_session->thread_id,
543
errmsg_printf(error::ERROR, _("Got an error from unknown thread, %s:%d"), sfile, sline);
457
sql_print_error(_("Got an error from unknown thread, %s:%d"), sfile, sline);
547
errmsg_printf(error::ERROR, "%s", message);
549
list<Session *>::iterator it= file->s->in_use->begin();
550
while (it != file->s->in_use->end())
459
sql_print_error("%s", message);
460
for (element= file->s->in_use; element; element= list_rest(element))
552
errmsg_printf(error::ERROR, "%s", _("Unknown thread accessing table"));
462
sql_print_error("%s", _("Unknown thread accessing table"));
557
ha_myisam::ha_myisam(plugin::StorageEngine &engine_arg,
559
: Cursor(engine_arg, table_arg),
561
can_enable_indexes(true),
565
Cursor *ha_myisam::clone(memory::Root *mem_root)
464
pthread_mutex_unlock(&file->s->intern_lock);
469
ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
470
:handler(hton, table_arg), file(0),
471
int_table_flags(HA_NULL_IN_KEY |
472
HA_BINLOG_ROW_CAPABLE |
473
HA_BINLOG_STMT_CAPABLE |
480
HA_STATS_RECORDS_IS_EXACT |
481
HA_NEED_READ_RANGE_BUFFER |
483
can_enable_indexes(1)
486
handler *ha_myisam::clone(MEM_ROOT *mem_root)
567
ha_myisam *new_handler= static_cast <ha_myisam *>(Cursor::clone(mem_root));
488
ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(mem_root));
569
490
new_handler->file->state= file->state;
570
491
return new_handler;
573
const char *ha_myisam::index_type(uint32_t )
495
static const char *ha_myisam_exts[] = {
501
const char **ha_myisam::bas_ext() const
503
return ha_myisam_exts;
507
const char *ha_myisam::index_type(uint32_t key_number __attribute__((unused)))
578
512
/* Name is here without an extension */
579
int ha_myisam::doOpen(const drizzled::identifier::Table &identifier, int mode, uint32_t test_if_locked)
513
int ha_myisam::open(const char *name, int mode, uint32_t test_if_locked)
581
515
MI_KEYDEF *keyinfo;
582
516
MI_COLUMNDEF *recinfo= 0;
598
532
open of a table that is in use by other threads already (if the
599
533
MyISAM share exists already).
601
if (!(file= mi_open(identifier, mode, test_if_locked)))
602
return (errno ? errno : -1);
604
if (!getTable()->getShare()->getType()) /* No need to perform a check for tmp table */
535
if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
536
return (my_errno ? my_errno : -1);
537
if (!table->s->tmp_table) /* No need to perform a check for tmp table */
606
if ((errno= table2myisam(getTable(), &keyinfo, &recinfo, &recs)))
539
if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
541
/* purecov: begin inspected */
610
if (check_definition(keyinfo, recinfo, getTable()->getShare()->sizeKeys(), recs,
545
if (check_definition(keyinfo, recinfo, table->s->keys, recs,
611
546
file->s->keyinfo, file->s->rec,
612
547
file->s->base.keys, file->s->base.fields, true))
614
errno= HA_ERR_CRASHED;
549
/* purecov: begin inspected */
550
my_errno= HA_ERR_CRASHED;
619
assert(test_if_locked);
620
556
if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
621
557
mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0);
623
559
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
624
560
if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
625
561
mi_extra(file, HA_EXTRA_WAIT_LOCK, 0);
626
if (!getTable()->getShare()->db_record_offset)
630
keys_with_parts.reset();
631
for (i= 0; i < getTable()->getShare()->sizeKeys(); i++)
562
if (!table->s->db_record_offset)
563
int_table_flags|=HA_REC_NOT_IN_SEQ;
564
if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
565
int_table_flags|=HA_HAS_CHECKSUM;
567
keys_with_parts.clear_all();
568
for (i= 0; i < table->s->keys; i++)
633
getTable()->key_info[i].block_size= file->s->keyinfo[i].block_length;
570
table->key_info[i].block_size= file->s->keyinfo[i].block_length;
635
KeyPartInfo *kp= getTable()->key_info[i].key_part;
636
KeyPartInfo *kp_end= kp + getTable()->key_info[i].key_parts;
572
KEY_PART_INFO *kp= table->key_info[i].key_part;
573
KEY_PART_INFO *kp_end= kp + table->key_info[i].key_parts;
637
574
for (; kp != kp_end; kp++)
639
if (!kp->field->part_of_key.test(i))
576
if (!kp->field->part_of_key.is_set(i))
641
keys_with_parts.set(i);
578
keys_with_parts.set_bit(i);
652
Both recinfo and keydef are allocated by multi_malloc(), thus only
589
Both recinfo and keydef are allocated by my_multi_malloc(), thus only
653
590
recinfo must be freed.
656
593
free((unsigned char*) recinfo);
660
597
int ha_myisam::close(void)
679
622
return mi_write(file,buf);
625
int ha_myisam::check(Session* session, HA_CHECK_OPT* check_opt)
627
if (!file) return HA_ADMIN_INTERNAL_ERROR;
630
MYISAM_SHARE* share = file->s;
631
const char *old_proc_info= session->get_proc_info();
633
session->set_proc_info("Checking table");
634
myisamchk_init(¶m);
635
param.session = session;
636
param.op_name = "check";
637
param.db_name= table->s->db.str;
638
param.table_name= table->alias;
639
param.testflag = check_opt->flags | T_CHECK | T_SILENT;
640
param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
642
if (!(table->db_stat & HA_READ_ONLY))
643
param.testflag|= T_STATISTICS;
644
param.using_global_keycache = 1;
646
if (!mi_is_crashed(file) &&
647
(((param.testflag & T_CHECK_ONLY_CHANGED) &&
648
!(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
649
STATE_CRASHED_ON_REPAIR)) &&
650
share->state.open_count == 0) ||
651
((param.testflag & T_FAST) && (share->state.open_count ==
652
(uint) (share->global_changed ? 1 : 0)))))
653
return HA_ADMIN_ALREADY_DONE;
655
error = chk_status(¶m, file); // Not fatal
656
error = chk_size(¶m, file);
658
error |= chk_del(¶m, file, param.testflag);
660
error = chk_key(¶m, file);
663
if ((!(param.testflag & T_QUICK) &&
665
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
666
(param.testflag & (T_EXTEND | T_MEDIUM)))) ||
669
uint32_t old_testflag=param.testflag;
670
param.testflag|=T_MEDIUM;
671
if (!(error= init_io_cache(¶m.read_cache, file->dfile,
672
my_default_record_cache_size, READ_CACHE,
673
share->pack.header_length, 1, MYF(MY_WME))))
675
error= chk_data_link(¶m, file, param.testflag & T_EXTEND);
676
end_io_cache(&(param.read_cache));
678
param.testflag= old_testflag;
683
if ((share->state.changed & (STATE_CHANGED |
684
STATE_CRASHED_ON_REPAIR |
685
STATE_CRASHED | STATE_NOT_ANALYZED)) ||
686
(param.testflag & T_STATISTICS) ||
689
file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
690
pthread_mutex_lock(&share->intern_lock);
691
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
692
STATE_CRASHED_ON_REPAIR);
693
if (!(table->db_stat & HA_READ_ONLY))
694
error=update_state_info(¶m,file,UPDATE_TIME | UPDATE_OPEN_COUNT |
696
pthread_mutex_unlock(&share->intern_lock);
697
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
701
else if (!mi_is_crashed(file) && !session->killed)
703
mi_mark_crashed(file);
704
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
707
session->set_proc_info(old_proc_info);
708
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
713
analyze the key distribution in the table
714
As the table may be only locked for read, we have to take into account that
715
two threads may do an analyze at the same time!
718
int ha_myisam::analyze(Session *session,
719
HA_CHECK_OPT* check_opt __attribute__((unused)))
723
MYISAM_SHARE* share = file->s;
725
myisamchk_init(¶m);
726
param.session = session;
727
param.op_name= "analyze";
728
param.db_name= table->s->db.str;
729
param.table_name= table->alias;
730
param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
731
T_DONT_CHECK_CHECKSUM);
732
param.using_global_keycache = 1;
733
param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
735
if (!(share->state.changed & STATE_NOT_ANALYZED))
736
return HA_ADMIN_ALREADY_DONE;
738
error = chk_key(¶m, file);
741
pthread_mutex_lock(&share->intern_lock);
742
error=update_state_info(¶m,file,UPDATE_STAT);
743
pthread_mutex_unlock(&share->intern_lock);
745
else if (!mi_is_crashed(file) && !session->killed)
746
mi_mark_crashed(file);
747
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
751
int ha_myisam::repair(Session* session, HA_CHECK_OPT *check_opt)
755
ha_rows start_records;
757
if (!file) return HA_ADMIN_INTERNAL_ERROR;
759
myisamchk_init(¶m);
760
param.session = session;
761
param.op_name= "repair";
762
param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
763
T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
764
(check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
765
param.sort_buffer_length= check_opt->sort_buffer_size;
766
start_records=file->state->records;
767
while ((error=repair(session,param,0)) && param.retry_repair)
769
param.retry_repair=0;
770
if (test_all_bits(param.testflag,
771
(uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
773
param.testflag&= ~T_RETRY_WITHOUT_QUICK;
774
sql_print_information("Retrying repair of: '%s' without quick",
778
param.testflag&= ~T_QUICK;
779
if ((param.testflag & T_REP_BY_SORT))
781
param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
782
sql_print_information("Retrying repair of: '%s' with keycache",
788
if (!error && start_records != file->state->records &&
789
!(check_opt->flags & T_VERY_SILENT))
791
char llbuff[22],llbuff2[22];
792
sql_print_information("Found %s of %s rows when repairing '%s'",
793
llstr(file->state->records, llbuff),
794
llstr(start_records, llbuff2),
800
int ha_myisam::optimize(Session* session, HA_CHECK_OPT *check_opt)
803
if (!file) return HA_ADMIN_INTERNAL_ERROR;
806
myisamchk_init(¶m);
807
param.session = session;
808
param.op_name= "optimize";
809
param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
810
T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
811
param.sort_buffer_length= check_opt->sort_buffer_size;
812
if ((error= repair(session,param,1)) && param.retry_repair)
814
sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying",
815
my_errno, param.db_name, param.table_name);
816
param.testflag&= ~T_REP_BY_SORT;
817
error= repair(session,param,1);
683
823
int ha_myisam::repair(Session *session, MI_CHECK ¶m, bool do_optimize)
686
uint32_t local_testflag= param.testflag;
826
uint32_t local_testflag=param.testflag;
687
827
bool optimize_done= !do_optimize, statistics_done=0;
688
828
const char *old_proc_info= session->get_proc_info();
689
829
char fixed_name[FN_REFLEN];
813
966
update_state_info(¶m, file, 0);
815
968
session->set_proc_info(old_proc_info);
816
mi_lock_database(file,F_UNLCK);
969
if (!session->locked_tables)
970
mi_lock_database(file,F_UNLCK);
818
971
return(error ? HA_ADMIN_FAILED :
819
972
!optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
977
Assign table indexes to a specific key cache.
980
int ha_myisam::assign_to_keycache(Session* session, HA_CHECK_OPT *check_opt)
982
KEY_CACHE *new_key_cache= check_opt->key_cache;
983
const char *errmsg= 0;
984
int error= HA_ADMIN_OK;
986
TableList *table_list= table->pos_in_table_list;
988
table->keys_in_use_for_query.clear_all();
990
if (table_list->process_index_hints(table))
991
return(HA_ADMIN_FAILED);
993
if (!table->keys_in_use_for_query.is_clear_all())
994
/* use all keys if there's no list specified by the user through hints */
995
map= table->keys_in_use_for_query.to_uint64_t();
997
if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
999
char buf[STRING_BUFFER_USUAL_SIZE];
1000
snprintf(buf, sizeof(buf),
1001
"Failed to flush to index file (errno: %d)", error);
1003
error= HA_ADMIN_CORRUPT;
1006
if (error != HA_ADMIN_OK)
1008
/* Send error to user */
1010
myisamchk_init(¶m);
1011
param.session= session;
1012
param.op_name= "assign_to_keycache";
1013
param.db_name= table->s->db.str;
1014
param.table_name= table->s->table_name.str;
1016
mi_check_print_error(¶m, errmsg);
824
1023
Disable indexes, making it persistent if requested.
1045
int ha_myisam::doUpdateRecord(const unsigned char *old_data, unsigned char *new_data)
1244
bool ha_myisam::check_and_repair(Session *session)
1249
uint32_t old_query_length;
1250
HA_CHECK_OPT check_opt;
1253
check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
1254
// Don't use quick if deleted rows
1255
if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
1256
check_opt.flags|=T_QUICK;
1257
sql_print_warning("Checking table: '%s'",table->s->path.str);
1259
old_query= session->query;
1260
old_query_length= session->query_length;
1261
pthread_mutex_lock(&LOCK_thread_count);
1262
session->query= table->s->table_name.str;
1263
session->query_length= table->s->table_name.length;
1264
pthread_mutex_unlock(&LOCK_thread_count);
1266
if ((marked_crashed= mi_is_crashed(file)) || check(session, &check_opt))
1268
sql_print_warning("Recovering table: '%s'",table->s->path.str);
1270
((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
1271
(marked_crashed ? 0 : T_QUICK) |
1272
(myisam_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
1274
if (repair(session, &check_opt))
1277
pthread_mutex_lock(&LOCK_thread_count);
1278
session->query= old_query;
1279
session->query_length= old_query_length;
1280
pthread_mutex_unlock(&LOCK_thread_count);
1284
bool ha_myisam::is_crashed() const
1286
return (file->s->state.changed & STATE_CRASHED ||
1287
(file->s->state.open_count));
1290
int ha_myisam::update_row(const unsigned char *old_data, unsigned char *new_data)
1292
ha_statistic_increment(&SSV::ha_update_count);
1293
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
1294
table->timestamp_field->set_time();
1047
1295
return mi_update(file,old_data,new_data);
1050
int ha_myisam::doDeleteRecord(const unsigned char *buf)
1298
int ha_myisam::delete_row(const unsigned char *buf)
1300
ha_statistic_increment(&SSV::ha_delete_count);
1052
1301
return mi_delete(file,buf);
1056
int ha_myisam::doStartIndexScan(uint32_t idx, bool )
1308
bool index_cond_func_myisam(void *arg)
1310
ha_myisam *h= (ha_myisam*)arg;
1311
/*if (h->in_range_read)*/
1314
if (h->compare_key2(h->end_range) > 0)
1315
return 2; /* caller should return HA_ERR_END_OF_FILE already */
1317
return (bool)h->pushed_idx_cond->val_int();
1325
int ha_myisam::index_init(uint32_t idx, bool sorted __attribute__((unused)))
1058
1327
active_index=idx;
1059
1328
//in_range_read= false;
1329
if (pushed_idx_cond_keyno == idx)
1330
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1064
int ha_myisam::doEndIndexScan()
1335
int ha_myisam::index_end()
1066
1337
active_index=MAX_KEY;
1338
//pushed_idx_cond_keyno= MAX_KEY;
1339
mi_set_index_cond_func(file, NULL, 0);
1340
in_range_check_pushed_down= false;
1341
ds_mrr.dsmrr_close();
1346
uint32_t ha_myisam::index_flags(uint32_t inx, uint32_t, bool) const
1348
return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ?
1349
0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
1350
HA_READ_ORDER | HA_KEYREAD_ONLY |
1351
(keys_with_parts.is_set(inx)?0:HA_DO_INDEX_COND_PUSHDOWN));
1093
1377
key_part_map keypart_map)
1095
1379
assert(inited==INDEX);
1096
ha_statistic_increment(&system_status_var::ha_read_key_count);
1380
ha_statistic_increment(&SSV::ha_read_key_count);
1097
1381
int error=mi_rkey(file, buf, active_index, key, keypart_map,
1098
1382
HA_READ_PREFIX_LAST);
1099
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1383
table->status=error ? STATUS_NOT_FOUND: 0;
1103
1387
int ha_myisam::index_next(unsigned char *buf)
1105
1389
assert(inited==INDEX);
1106
ha_statistic_increment(&system_status_var::ha_read_next_count);
1390
ha_statistic_increment(&SSV::ha_read_next_count);
1107
1391
int error=mi_rnext(file,buf,active_index);
1108
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1392
table->status=error ? STATUS_NOT_FOUND: 0;
1112
1396
int ha_myisam::index_prev(unsigned char *buf)
1114
1398
assert(inited==INDEX);
1115
ha_statistic_increment(&system_status_var::ha_read_prev_count);
1399
ha_statistic_increment(&SSV::ha_read_prev_count);
1116
1400
int error=mi_rprev(file,buf, active_index);
1117
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1401
table->status=error ? STATUS_NOT_FOUND: 0;
1121
1405
int ha_myisam::index_first(unsigned char *buf)
1123
1407
assert(inited==INDEX);
1124
ha_statistic_increment(&system_status_var::ha_read_first_count);
1408
ha_statistic_increment(&SSV::ha_read_first_count);
1125
1409
int error=mi_rfirst(file, buf, active_index);
1126
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1410
table->status=error ? STATUS_NOT_FOUND: 0;
1130
1414
int ha_myisam::index_last(unsigned char *buf)
1132
1416
assert(inited==INDEX);
1133
ha_statistic_increment(&system_status_var::ha_read_last_count);
1417
ha_statistic_increment(&SSV::ha_read_last_count);
1134
1418
int error=mi_rlast(file, buf, active_index);
1135
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1419
table->status=error ? STATUS_NOT_FOUND: 0;
1139
1423
int ha_myisam::index_next_same(unsigned char *buf,
1140
const unsigned char *,
1424
const unsigned char *key __attribute__((unused)),
1425
uint32_t length __attribute__((unused)))
1144
1428
assert(inited==INDEX);
1145
ha_statistic_increment(&system_status_var::ha_read_next_count);
1429
ha_statistic_increment(&SSV::ha_read_next_count);
1148
1432
error= mi_rnext_same(file,buf);
1149
1433
} while (error == HA_ERR_RECORD_DELETED);
1150
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1434
table->status=error ? STATUS_NOT_FOUND: 0;
1226
1515
if (flag & HA_STATUS_CONST)
1228
TableShare *share= getTable()->getMutableShare();
1517
TABLE_SHARE *share= table->s;
1229
1518
stats.max_data_file_length= misam_info.max_data_file_length;
1230
1519
stats.max_index_file_length= misam_info.max_index_file_length;
1231
1520
stats.create_time= misam_info.create_time;
1232
1521
ref_length= misam_info.reflength;
1233
1522
share->db_options_in_use= misam_info.options;
1234
stats.block_size= myisam_key_cache_block_size; /* record block size */
1523
stats.block_size= myisam_block_size; /* record block size */
1236
set_prefix(share->keys_in_use, share->sizeKeys());
1238
* Due to bug 394932 (32-bit solaris build failure), we need
1239
* to convert the uint64_t key_map member of the misam_info
1240
* structure in to a std::bitset so that we can logically and
1241
* it with the share->key_in_use key_map.
1244
string binary_key_map;
1245
uint64_t num= misam_info.key_map;
1247
* Convert the uint64_t to a binary
1248
* string representation of it.
1252
uint64_t bin_digit= num % 2;
1256
binary_key_map.append(ostr.str());
1258
* Now we have the binary string representation of the
1259
* flags, we need to fill that string representation out
1260
* with the appropriate number of bits. This is needed
1261
* since key_map is declared as a std::bitset of a certain bit
1262
* width that depends on the MAX_INDEXES variable.
1264
if (MAX_INDEXES <= 64)
1266
size_t len= 72 - binary_key_map.length();
1267
string all_zeros(len, '0');
1268
binary_key_map.insert(binary_key_map.begin(),
1274
size_t len= (MAX_INDEXES + 7) / 8 * 8;
1275
string all_zeros(len, '0');
1276
binary_key_map.insert(binary_key_map.begin(),
1280
key_map tmp_map(binary_key_map);
1281
share->keys_in_use&= tmp_map;
1282
share->keys_for_keyread&= share->keys_in_use;
1526
if (share->tmp_table == NO_TMP_TABLE)
1527
pthread_mutex_lock(&share->mutex);
1528
share->keys_in_use.set_prefix(share->keys);
1529
share->keys_in_use.intersect_extended(misam_info.key_map);
1530
share->keys_for_keyread.intersect(share->keys_in_use);
1283
1531
share->db_record_offset= misam_info.record_offset;
1284
1532
if (share->key_parts)
1285
memcpy(getTable()->key_info[0].rec_per_key,
1533
memcpy(table->key_info[0].rec_per_key,
1286
1534
misam_info.rec_per_key,
1287
sizeof(getTable()->key_info[0].rec_per_key)*share->key_parts);
1288
assert(share->getType() != message::Table::STANDARD);
1535
sizeof(table->key_info[0].rec_per_key)*share->key_parts);
1536
if (share->tmp_table == NO_TMP_TABLE)
1537
pthread_mutex_unlock(&share->mutex);
1291
1540
Set data_file_name and index_file_name to point at the symlink value
1292
1541
if table is symlinked (Ie; Real name is not same as generated name)
1294
1543
data_file_name= index_file_name= 0;
1295
internal::fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1544
fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1296
1545
MY_APPEND_EXT | MY_UNPACK_FILENAME);
1297
1546
if (strcmp(name_buff, misam_info.data_file_name))
1298
1547
data_file_name=misam_info.data_file_name;
1299
internal::fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1548
fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1300
1549
MY_APPEND_EXT | MY_UNPACK_FILENAME);
1301
1550
if (strcmp(name_buff, misam_info.index_file_name))
1302
1551
index_file_name=misam_info.index_file_name;
1337
1590
return mi_delete_all_rows(file);
1340
int MyisamEngine::doDropTable(Session &session,
1341
const identifier::Table &identifier)
1593
int ha_myisam::delete_table(const char *name)
1343
session.getMessageCache().removeTableMessage(identifier);
1345
return mi_delete_table(identifier.getPath().c_str());
1595
return mi_delete_table(name);
1349
1599
int ha_myisam::external_lock(Session *session, int lock_type)
1351
file->in_use= session;
1352
return mi_lock_database(file, !getTable()->getShare()->getType() ?
1601
file->in_use.data= session;
1602
return mi_lock_database(file, !table->s->tmp_table ?
1353
1603
lock_type : ((lock_type == F_UNLCK) ?
1354
1604
F_UNLCK : F_EXTRA_LCK));
1357
int MyisamEngine::doCreateTable(Session &session,
1359
const identifier::Table &identifier,
1360
message::Table& create_proto)
1607
THR_LOCK_DATA **ha_myisam::store_lock(Session *session __attribute__((unused)),
1609
enum thr_lock_type lock_type)
1611
if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
1612
file->lock.type=lock_type;
1617
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
1619
ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
1620
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
1622
create_info->auto_increment_value= stats.auto_increment_value;
1624
create_info->data_file_name=data_file_name;
1625
create_info->index_file_name=index_file_name;
1629
int ha_myisam::create(const char *name, register Table *table_arg,
1630
HA_CREATE_INFO *ha_create_info)
1363
uint32_t create_flags= 0, create_records;
1633
uint32_t create_flags= 0, records;
1364
1634
char buff[FN_REFLEN];
1365
1635
MI_KEYDEF *keydef;
1366
1636
MI_COLUMNDEF *recinfo;
1367
1637
MI_CREATE_INFO create_info;
1368
TableShare *share= table_arg.getMutableShare();
1638
TABLE_SHARE *share= table_arg->s;
1369
1639
uint32_t options= share->db_options_in_use;
1370
if ((error= table2myisam(&table_arg, &keydef, &recinfo, &create_records)))
1640
if ((error= table2myisam(table_arg, &keydef, &recinfo, &records)))
1641
return(error); /* purecov: inspected */
1372
1642
memset(&create_info, 0, sizeof(create_info));
1373
create_info.max_rows= create_proto.options().max_rows();
1374
create_info.reloc_rows= create_proto.options().min_rows();
1643
create_info.max_rows= share->max_rows;
1644
create_info.reloc_rows= share->min_rows;
1375
1645
create_info.with_auto_increment= share->next_number_key_offset == 0;
1376
create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
1377
create_proto.options().auto_increment_value() -1 :
1646
create_info.auto_increment= (ha_create_info->auto_increment_value ?
1647
ha_create_info->auto_increment_value -1 :
1379
create_info.data_file_length= (create_proto.options().max_rows() *
1380
create_proto.options().avg_row_length());
1381
create_info.data_file_name= NULL;
1382
create_info.index_file_name= NULL;
1649
create_info.data_file_length= ((uint64_t) share->max_rows *
1650
share->avg_row_length);
1651
create_info.data_file_name= ha_create_info->data_file_name;
1652
create_info.index_file_name= ha_create_info->index_file_name;
1383
1653
create_info.language= share->table_charset->number;
1385
if (create_proto.type() == message::Table::TEMPORARY)
1655
if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
1386
1656
create_flags|= HA_CREATE_TMP_TABLE;
1657
if (ha_create_info->options & HA_CREATE_KEEP_FILES)
1658
create_flags|= HA_CREATE_KEEP_FILES;
1387
1659
if (options & HA_OPTION_PACK_RECORD)
1388
1660
create_flags|= HA_PACK_RECORD;
1661
if (options & HA_OPTION_CHECKSUM)
1662
create_flags|= HA_CREATE_CHECKSUM;
1663
if (options & HA_OPTION_DELAY_KEY_WRITE)
1664
create_flags|= HA_CREATE_DELAY_KEY_WRITE;
1390
/* TODO: Check that the following internal::fn_format is really needed */
1391
error= mi_create(internal::fn_format(buff, identifier.getPath().c_str(), "", "",
1392
MY_UNPACK_FILENAME|MY_APPEND_EXT),
1393
share->sizeKeys(), keydef,
1394
create_records, recinfo,
1666
/* TODO: Check that the following fn_format is really needed */
1667
error= mi_create(fn_format(buff, name, "", "",
1668
MY_UNPACK_FILENAME|MY_APPEND_EXT),
1669
share->keys, keydef,
1395
1671
0, (MI_UNIQUEDEF*) 0,
1396
1672
&create_info, create_flags);
1397
1673
free((unsigned char*) recinfo);
1399
session.getMessageCache().storeTableMessage(identifier, create_proto);
1405
int MyisamEngine::doRenameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
1678
int ha_myisam::rename_table(const char * from, const char * to)
1407
session.getMessageCache().renameTableMessage(from, to);
1409
return mi_rename(from.getPath().c_str(), to.getPath().c_str());
1680
return mi_rename(from,to);
1413
void ha_myisam::get_auto_increment(uint64_t ,
1684
void ha_myisam::get_auto_increment(uint64_t offset __attribute__((unused)),
1685
uint64_t increment __attribute__((unused)),
1686
uint64_t nb_desired_values __attribute__((unused)),
1416
1687
uint64_t *first_value,
1417
1688
uint64_t *nb_reserved_values)
1432
1703
/* it's safe to call the following if bulk_insert isn't on */
1433
mi_flush_bulk_insert(file, getTable()->getShare()->next_number_index);
1704
mi_flush_bulk_insert(file, table->s->next_number_index);
1435
1706
(void) extra(HA_EXTRA_KEYREAD);
1436
key_copy(key, getTable()->getInsertRecord(),
1437
&getTable()->key_info[getTable()->getShare()->next_number_index],
1438
getTable()->getShare()->next_number_key_offset);
1439
error= mi_rkey(file, getTable()->getUpdateRecord(), (int) getTable()->getShare()->next_number_index,
1440
key, make_prev_keypart_map(getTable()->getShare()->next_number_keypart),
1707
key_copy(key, table->record[0],
1708
table->key_info + table->s->next_number_index,
1709
table->s->next_number_key_offset);
1710
error= mi_rkey(file, table->record[1], (int) table->s->next_number_index,
1711
key, make_prev_keypart_map(table->s->next_number_keypart),
1441
1712
HA_READ_PREFIX_LAST);
1446
/* Get data from getUpdateRecord() */
1447
nr= ((uint64_t) getTable()->next_number_field->
1448
val_int_offset(getTable()->getShare()->rec_buff_length)+1);
1717
/* Get data from record[1] */
1718
nr= ((uint64_t) table->next_number_field->
1719
val_int_offset(table->s->rec_buff_length)+1);
1450
1721
extra(HA_EXTRA_NO_KEYREAD);
1451
1722
*first_value= nr;
1496
1767
return (uint)file->state->checksum;
1499
static int myisam_init(module::Context &context)
1501
context.add(new MyisamEngine(engine_name));
1502
context.registerVariable(new sys_var_constrained_value<size_t>("sort-buffer-size",
1504
context.registerVariable(new sys_var_uint64_t_ptr("max_sort_file_size",
1505
&max_sort_file_size,
1506
context.getOptions()["max-sort-file-size"].as<uint64_t>()));
1771
bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *info,
1772
uint32_t table_changes)
1774
uint32_t options= table->s->db_options_in_use;
1776
if (info->auto_increment_value != stats.auto_increment_value ||
1777
info->data_file_name != data_file_name ||
1778
info->index_file_name != index_file_name ||
1779
table_changes == IS_EQUAL_NO ||
1780
table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
1781
return COMPATIBLE_DATA_NO;
1783
if ((options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1784
HA_OPTION_DELAY_KEY_WRITE)) !=
1785
(info->table_options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
1786
HA_OPTION_DELAY_KEY_WRITE)))
1787
return COMPATIBLE_DATA_NO;
1788
return COMPATIBLE_DATA_YES;
1791
int myisam_deinit(void *hton __attribute__((unused)))
1793
pthread_mutex_destroy(&THR_LOCK_myisam);
1795
return mi_panic(HA_PANIC_CLOSE);
1798
static int myisam_init(void *p)
1800
handlerton *myisam_hton;
1802
myisam_hton= (handlerton *)p;
1803
myisam_hton->state= SHOW_OPTION_YES;
1804
myisam_hton->create= myisam_create_handler;
1805
myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
1512
static void init_options(drizzled::module::option_context &context)
1514
context("max-sort-file-size",
1515
po::value<uint64_t>(&max_sort_file_size)->default_value(INT32_MAX),
1516
_("Don't use the fast sort index method to created index if the temporary file would get bigger than this."));
1517
context("sort-buffer-size",
1518
po::value<sort_buffer_constraint>(&sort_buffer_size)->default_value(8192*1024),
1519
_("The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE."));
1523
DRIZZLE_DECLARE_PLUGIN
1811
/****************************************************************************
1812
* MyISAM MRR implementation: use DS-MRR
1813
***************************************************************************/
1815
int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
1816
uint32_t n_ranges, uint32_t mode,
1817
HANDLER_BUFFER *buf)
1819
return ds_mrr.dsmrr_init(this, &table->key_info[active_index],
1820
seq, seq_init_param, n_ranges, mode, buf);
1823
int ha_myisam::multi_range_read_next(char **range_info)
1825
return ds_mrr.dsmrr_next(this, range_info);
1828
ha_rows ha_myisam::multi_range_read_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
1829
void *seq_init_param,
1830
uint32_t n_ranges, uint32_t *bufsz,
1831
uint32_t *flags, COST_VECT *cost)
1834
This call is here because there is no location where this->table would
1836
TODO: consider moving it into some per-query initialization call.
1838
ds_mrr.init(this, table);
1839
return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz,
1843
int ha_myisam::multi_range_read_info(uint32_t keyno, uint32_t n_ranges, uint32_t keys,
1844
uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
1846
ds_mrr.init(this, table);
1847
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
1850
/* MyISAM MRR implementation ends */
1853
/* Index condition pushdown implementation*/
1856
Item *ha_myisam::idx_cond_push(uint32_t keyno_arg, Item* idx_cond_arg)
1858
pushed_idx_cond_keyno= keyno_arg;
1859
pushed_idx_cond= idx_cond_arg;
1860
in_range_check_pushed_down= true;
1861
if (active_index == pushed_idx_cond_keyno)
1862
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1867
mysql_declare_plugin(myisam)
1869
DRIZZLE_STORAGE_ENGINE_PLUGIN,
1529
1873
"Default engine as of MySQL 3.23 with great performance",
1530
1874
PLUGIN_LICENSE_GPL,
1531
1875
myisam_init, /* Plugin Init */
1533
init_options /* config options */
1876
myisam_deinit, /* Plugin Deinit */
1877
NULL, /* status variables */
1878
NULL, /* system variables */
1879
NULL /* config options */
1535
DRIZZLE_DECLARE_PLUGIN_END;
1881
mysql_declare_plugin_end;