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"
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
#include <drizzled/server_includes.h>
19
#include <mysys/my_bit.h>
20
20
#include "myisampack.h"
21
21
#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>
22
#include "myisamdef.h"
23
#include <drizzled/util/test.h>
24
#include <drizzled/error.h>
25
#include <drizzled/errmsg_print.h>
26
#include <drizzled/gettext.h>
27
#include <drizzled/session.h>
28
#include <drizzled/protocol.h>
29
#include <drizzled/table.h>
30
#include <drizzled/field/timestamp.h>
46
#include <boost/program_options.hpp>
47
#include <drizzled/module/option_map.h>
49
namespace po= boost::program_options;
51
34
using namespace std;
52
using namespace drizzled;
54
36
static const string engine_name("MyISAM");
56
boost::mutex THR_LOCK_myisam;
38
ulong myisam_recover_options= HA_RECOVER_NONE;
39
pthread_mutex_t THR_LOCK_myisam= PTHREAD_MUTEX_INITIALIZER;
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;
41
static uint32_t repair_threads;
42
static uint32_t block_size;
62
43
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);
44
static uint64_t sort_buffer_size;
46
/* bits in myisam_recover_options */
47
const char *myisam_recover_names[] =
48
{ "DEFAULT", "BACKUP", "FORCE", "QUICK", NULL};
49
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
50
myisam_recover_names, NULL};
52
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
53
"nulls_ignored", NULL};
54
TYPELIB myisam_stats_method_typelib= {
55
array_elements(myisam_stats_method_names) - 1, "",
56
myisam_stats_method_names, NULL};
75
59
/*****************************************************************************
85
class MyisamEngine : public plugin::StorageEngine
69
class MyisamEngine : public 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);
72
MyisamEngine(string name_arg)
73
: StorageEngine(name_arg, HTON_CAN_RECREATE) {}
75
virtual handler *create(TableShare *table,
78
return new (mem_root) ha_myisam(this, table);
114
81
const char **bas_ext() const {
115
82
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"))
85
int createTableImpl(Session *, const char *table_name,
86
Table *table_arg, HA_CREATE_INFO *ha_create_info);
88
int renameTableImpl(Session*, const char *from, const char *to);
90
int deleteTableImpl(Session*, const string table_name);
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 )
93
// collect errors printed by mi_check routines
95
static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
96
const char *fmt, va_list args)
98
Session* session = (Session*)param->session;
99
Protocol *protocol= session->protocol;
100
uint32_t length, msg_length;
101
char msgbuf[MI_MAX_MSG_BUF];
102
char name[NAME_LEN*2+2];
104
msg_length= vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
105
msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
107
if (!session->protocol->isConnected())
109
errmsg_printf(ERRMSG_LVL_ERROR, "%s",msgbuf);
113
if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
116
my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
119
length= sprintf(name,"%s.%s",param->db_name,param->table_name);
122
TODO: switch from protocol to push_warning here. The main reason we didn't
123
it yet is parallel repair. Due to following trace:
124
mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
126
Also we likely need to lock mutex here (in both cases with protocol and
129
protocol->prepareForResend();
130
protocol->store(name, length, system_charset_info);
131
protocol->store(param->op_name, system_charset_info);
132
protocol->store(msg_type, system_charset_info);
133
protocol->store(msgbuf, msg_length, system_charset_info);
134
if (protocol->write())
135
errmsg_printf(ERRMSG_LVL_ERROR, "Failed on drizzleclient_net_write, writing to stderr instead: %s\n",
214
static int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
215
MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
165
int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
166
MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
217
168
uint32_t i, j, recpos, minpos, fieldpos, temp_length, length;
218
169
enum ha_base_keytype type= HA_KEYTYPE_BINARY;
219
170
unsigned char *record;
220
172
MI_KEYDEF *keydef;
221
173
MI_COLUMNDEF *recinfo, *recinfo_pos;
222
174
HA_KEYSEG *keyseg;
223
TableShare *share= table_arg->getMutableShare();
175
TableShare *share= table_arg->s;
224
176
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),
177
if (!(my_multi_malloc(MYF(MY_WME),
178
recinfo_out, (share->fields * 2 + 2) * sizeof(MI_COLUMNDEF),
179
keydef_out, share->keys * sizeof(MI_KEYDEF),
181
(share->key_parts + share->keys) * sizeof(HA_KEYSEG),
230
return(HA_ERR_OUT_OF_MEM);
183
return(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
231
184
keydef= *keydef_out;
232
185
recinfo= *recinfo_out;
233
for (i= 0; i < share->sizeKeys(); i++)
186
pos= table_arg->key_info;
187
for (i= 0; i < share->keys; i++, pos++)
235
KeyInfo *pos= &table_arg->key_info[i];
236
189
keydef[i].flag= ((uint16_t) pos->flags & (HA_NOSAME));
237
190
keydef[i].key_alg= HA_KEY_ALG_BTREE;
238
191
keydef[i].block_length= pos->block_size;
589
551
open of a table that is in use by other threads already (if the
590
552
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 */
554
if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
555
return (my_errno ? my_errno : -1);
556
if (!table->s->tmp_table) /* No need to perform a check for tmp table */
597
if ((errno= table2myisam(getTable(), &keyinfo, &recinfo, &recs)))
558
if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
560
/* purecov: begin inspected */
601
if (check_definition(keyinfo, recinfo, getTable()->getShare()->sizeKeys(), recs,
564
if (check_definition(keyinfo, recinfo, table->s->keys, recs,
602
565
file->s->keyinfo, file->s->rec,
603
566
file->s->base.keys, file->s->base.fields, true))
605
errno= HA_ERR_CRASHED;
568
/* purecov: begin inspected */
569
my_errno= HA_ERR_CRASHED;
610
assert(test_if_locked);
611
575
if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
612
576
mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0);
614
578
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
615
579
if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
616
580
mi_extra(file, HA_EXTRA_WAIT_LOCK, 0);
617
if (!getTable()->getShare()->db_record_offset)
581
if (!table->s->db_record_offset)
582
int_table_flags|=HA_REC_NOT_IN_SEQ;
583
if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
584
int_table_flags|=HA_HAS_CHECKSUM;
621
586
keys_with_parts.reset();
622
for (i= 0; i < getTable()->getShare()->sizeKeys(); i++)
587
for (i= 0; i < table->s->keys; i++)
624
getTable()->key_info[i].block_size= file->s->keyinfo[i].block_length;
589
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;
591
KEY_PART_INFO *kp= table->key_info[i].key_part;
592
KEY_PART_INFO *kp_end= kp + table->key_info[i].key_parts;
628
593
for (; kp != kp_end; kp++)
630
595
if (!kp->field->part_of_key.test(i))
670
637
return mi_write(file,buf);
640
int ha_myisam::check(Session* session, HA_CHECK_OPT* check_opt)
642
if (!file) return HA_ADMIN_INTERNAL_ERROR;
645
MYISAM_SHARE* share = file->s;
646
const char *old_proc_info= session->get_proc_info();
648
session->set_proc_info("Checking table");
649
myisamchk_init(¶m);
650
param.session = session;
651
param.op_name = "check";
652
param.db_name= table->s->db.str;
653
param.table_name= table->alias;
654
param.testflag = check_opt->flags | T_CHECK | T_SILENT;
655
param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
657
if (!(table->db_stat & HA_READ_ONLY))
658
param.testflag|= T_STATISTICS;
659
param.using_global_keycache = 1;
661
if (!mi_is_crashed(file) &&
662
(((param.testflag & T_CHECK_ONLY_CHANGED) &&
663
!(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
664
STATE_CRASHED_ON_REPAIR)) &&
665
share->state.open_count == 0) ||
666
((param.testflag & T_FAST) && (share->state.open_count ==
667
(uint) (share->global_changed ? 1 : 0)))))
668
return HA_ADMIN_ALREADY_DONE;
670
error = chk_status(¶m, file); // Not fatal
671
error = chk_size(¶m, file);
673
error |= chk_del(¶m, file, param.testflag);
675
error = chk_key(¶m, file);
678
if ((!(param.testflag & T_QUICK) &&
680
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
681
(param.testflag & (T_EXTEND | T_MEDIUM)))) ||
684
uint32_t old_testflag=param.testflag;
685
param.testflag|=T_MEDIUM;
686
if (!(error= init_io_cache(¶m.read_cache, file->dfile,
687
my_default_record_cache_size, READ_CACHE,
688
share->pack.header_length, 1, MYF(MY_WME))))
690
error= chk_data_link(¶m, file, param.testflag & T_EXTEND);
691
end_io_cache(&(param.read_cache));
693
param.testflag= old_testflag;
698
if ((share->state.changed & (STATE_CHANGED |
699
STATE_CRASHED_ON_REPAIR |
700
STATE_CRASHED | STATE_NOT_ANALYZED)) ||
701
(param.testflag & T_STATISTICS) ||
704
file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
705
pthread_mutex_lock(&share->intern_lock);
706
share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
707
STATE_CRASHED_ON_REPAIR);
708
if (!(table->db_stat & HA_READ_ONLY))
709
error=update_state_info(¶m,file,UPDATE_TIME | UPDATE_OPEN_COUNT |
711
pthread_mutex_unlock(&share->intern_lock);
712
info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
716
else if (!mi_is_crashed(file) && !session->killed)
718
mi_mark_crashed(file);
719
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
722
session->set_proc_info(old_proc_info);
723
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
728
analyze the key distribution in the table
729
As the table may be only locked for read, we have to take into account that
730
two threads may do an analyze at the same time!
733
int ha_myisam::analyze(Session *session,
738
MYISAM_SHARE* share = file->s;
740
myisamchk_init(¶m);
741
param.session = session;
742
param.op_name= "analyze";
743
param.db_name= table->s->db.str;
744
param.table_name= table->alias;
745
param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
746
T_DONT_CHECK_CHECKSUM);
747
param.using_global_keycache = 1;
748
param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
750
if (!(share->state.changed & STATE_NOT_ANALYZED))
751
return HA_ADMIN_ALREADY_DONE;
753
error = chk_key(¶m, file);
756
pthread_mutex_lock(&share->intern_lock);
757
error=update_state_info(¶m,file,UPDATE_STAT);
758
pthread_mutex_unlock(&share->intern_lock);
760
else if (!mi_is_crashed(file) && !session->killed)
761
mi_mark_crashed(file);
762
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
766
int ha_myisam::repair(Session* session, HA_CHECK_OPT *check_opt)
770
ha_rows start_records;
772
if (!file) return HA_ADMIN_INTERNAL_ERROR;
774
myisamchk_init(¶m);
775
param.session = session;
776
param.op_name= "repair";
777
param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
778
T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
779
(check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
780
param.sort_buffer_length= (size_t)sort_buffer_size;
782
// Release latches since this can take a long time
783
ha_release_temporary_latches(session);
785
start_records=file->state->records;
786
while ((error=repair(session,param,0)) && param.retry_repair)
788
param.retry_repair=0;
789
if (test_all_bits(param.testflag,
790
(uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
792
param.testflag&= ~T_RETRY_WITHOUT_QUICK;
793
errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' without quick",
797
param.testflag&= ~T_QUICK;
798
if ((param.testflag & T_REP_BY_SORT))
800
param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
801
errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' with keycache",
807
if (!error && start_records != file->state->records &&
808
!(check_opt->flags & T_VERY_SILENT))
810
char llbuff[22],llbuff2[22];
811
errmsg_printf(ERRMSG_LVL_INFO, "Found %s of %s rows when repairing '%s'",
812
llstr(file->state->records, llbuff),
813
llstr(start_records, llbuff2),
819
int ha_myisam::optimize(Session* session, HA_CHECK_OPT *check_opt)
822
if (!file) return HA_ADMIN_INTERNAL_ERROR;
825
myisamchk_init(¶m);
826
param.session = session;
827
param.op_name= "optimize";
828
param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
829
T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
830
param.sort_buffer_length= (size_t)sort_buffer_size;
831
if ((error= repair(session,param,1)) && param.retry_repair)
833
errmsg_printf(ERRMSG_LVL_WARN, "Warning: Optimize table got errno %d on %s.%s, retrying",
834
my_errno, param.db_name, param.table_name);
835
param.testflag&= ~T_REP_BY_SORT;
836
error= repair(session,param,1);
674
842
int ha_myisam::repair(Session *session, MI_CHECK ¶m, bool do_optimize)
804
985
update_state_info(¶m, file, 0);
806
987
session->set_proc_info(old_proc_info);
807
mi_lock_database(file,F_UNLCK);
988
if (!session->locked_tables)
989
mi_lock_database(file,F_UNLCK);
809
990
return(error ? HA_ADMIN_FAILED :
810
991
!optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
996
Assign table indexes to a specific key cache.
999
int ha_myisam::assign_to_keycache(Session* session, HA_CHECK_OPT *check_opt)
1001
KEY_CACHE *new_key_cache= check_opt->key_cache;
1002
const char *errmsg= 0;
1003
int error= HA_ADMIN_OK;
1004
TableList *table_list= table->pos_in_table_list;
1006
table->keys_in_use_for_query.reset();
1008
if (table_list->process_index_hints(table))
1009
return(HA_ADMIN_FAILED);
1011
if ((error= mi_assign_to_key_cache(file, new_key_cache)))
1013
char buf[STRING_BUFFER_USUAL_SIZE];
1014
snprintf(buf, sizeof(buf),
1015
"Failed to flush to index file (errno: %d)", error);
1017
error= HA_ADMIN_CORRUPT;
1020
if (error != HA_ADMIN_OK)
1022
/* Send error to user */
1024
myisamchk_init(¶m);
1025
param.session= session;
1026
param.op_name= "assign_to_keycache";
1027
param.db_name= table->s->db.str;
1028
param.table_name= table->s->table_name.str;
1030
mi_check_print_error(¶m, errmsg);
815
1037
Disable indexes, making it persistent if requested.
1036
int ha_myisam::doUpdateRecord(const unsigned char *old_data, unsigned char *new_data)
1259
bool ha_myisam::check_and_repair(Session *session)
1264
uint32_t old_query_length;
1265
HA_CHECK_OPT check_opt;
1268
check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
1269
// Don't use quick if deleted rows
1270
if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
1271
check_opt.flags|=T_QUICK;
1272
errmsg_printf(ERRMSG_LVL_WARN, "Checking table: '%s'",table->s->path.str);
1274
old_query= session->query;
1275
old_query_length= session->query_length;
1276
pthread_mutex_lock(&LOCK_thread_count);
1277
session->query= table->s->table_name.str;
1278
session->query_length= table->s->table_name.length;
1279
pthread_mutex_unlock(&LOCK_thread_count);
1281
if ((marked_crashed= mi_is_crashed(file)) || check(session, &check_opt))
1283
errmsg_printf(ERRMSG_LVL_WARN, "Recovering table: '%s'",table->s->path.str);
1285
((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
1286
(marked_crashed ? 0 : T_QUICK) |
1287
(myisam_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
1289
if (repair(session, &check_opt))
1292
pthread_mutex_lock(&LOCK_thread_count);
1293
session->query= old_query;
1294
session->query_length= old_query_length;
1295
pthread_mutex_unlock(&LOCK_thread_count);
1299
bool ha_myisam::is_crashed() const
1301
return (file->s->state.changed & STATE_CRASHED ||
1302
(file->s->state.open_count));
1305
int ha_myisam::update_row(const unsigned char *old_data, unsigned char *new_data)
1307
ha_statistic_increment(&SSV::ha_update_count);
1308
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
1309
table->timestamp_field->set_time();
1038
1310
return mi_update(file,old_data,new_data);
1041
int ha_myisam::doDeleteRecord(const unsigned char *buf)
1313
int ha_myisam::delete_row(const unsigned char *buf)
1315
ha_statistic_increment(&SSV::ha_delete_count);
1043
1316
return mi_delete(file,buf);
1047
int ha_myisam::doStartIndexScan(uint32_t idx, bool )
1323
bool index_cond_func_myisam(void *arg)
1325
ha_myisam *h= (ha_myisam*)arg;
1326
/*if (h->in_range_read)*/
1329
if (h->compare_key2(h->end_range) > 0)
1330
return 2; /* caller should return HA_ERR_END_OF_FILE already */
1332
return (bool)h->pushed_idx_cond->val_int();
1340
int ha_myisam::index_init(uint32_t idx, bool )
1049
1342
active_index=idx;
1050
1343
//in_range_read= false;
1344
if (pushed_idx_cond_keyno == idx)
1345
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1055
int ha_myisam::doEndIndexScan()
1350
int ha_myisam::index_end()
1057
1352
active_index=MAX_KEY;
1353
//pushed_idx_cond_keyno= MAX_KEY;
1354
mi_set_index_cond_func(file, NULL, 0);
1355
in_range_check_pushed_down= false;
1356
ds_mrr.dsmrr_close();
1361
uint32_t ha_myisam::index_flags(uint32_t inx, uint32_t, bool) const
1363
return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ?
1364
0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
1365
HA_READ_ORDER | HA_KEYREAD_ONLY |
1366
(keys_with_parts.test(inx)?0:HA_DO_INDEX_COND_PUSHDOWN));
1062
1370
int ha_myisam::index_read_map(unsigned char *buf, const unsigned char *key,
1063
1371
key_part_map keypart_map,
1064
1372
enum ha_rkey_function find_flag)
1066
1374
assert(inited==INDEX);
1067
ha_statistic_increment(&system_status_var::ha_read_key_count);
1375
ha_statistic_increment(&SSV::ha_read_key_count);
1068
1376
int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
1069
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1377
table->status=error ? STATUS_NOT_FOUND: 0;
1084
1392
key_part_map keypart_map)
1086
1394
assert(inited==INDEX);
1087
ha_statistic_increment(&system_status_var::ha_read_key_count);
1395
ha_statistic_increment(&SSV::ha_read_key_count);
1088
1396
int error=mi_rkey(file, buf, active_index, key, keypart_map,
1089
1397
HA_READ_PREFIX_LAST);
1090
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1398
table->status=error ? STATUS_NOT_FOUND: 0;
1094
1402
int ha_myisam::index_next(unsigned char *buf)
1096
1404
assert(inited==INDEX);
1097
ha_statistic_increment(&system_status_var::ha_read_next_count);
1405
ha_statistic_increment(&SSV::ha_read_next_count);
1098
1406
int error=mi_rnext(file,buf,active_index);
1099
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1407
table->status=error ? STATUS_NOT_FOUND: 0;
1103
1411
int ha_myisam::index_prev(unsigned char *buf)
1105
1413
assert(inited==INDEX);
1106
ha_statistic_increment(&system_status_var::ha_read_prev_count);
1414
ha_statistic_increment(&SSV::ha_read_prev_count);
1107
1415
int error=mi_rprev(file,buf, active_index);
1108
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1416
table->status=error ? STATUS_NOT_FOUND: 0;
1112
1420
int ha_myisam::index_first(unsigned char *buf)
1114
1422
assert(inited==INDEX);
1115
ha_statistic_increment(&system_status_var::ha_read_first_count);
1423
ha_statistic_increment(&SSV::ha_read_first_count);
1116
1424
int error=mi_rfirst(file, buf, active_index);
1117
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1425
table->status=error ? STATUS_NOT_FOUND: 0;
1121
1429
int ha_myisam::index_last(unsigned char *buf)
1123
1431
assert(inited==INDEX);
1124
ha_statistic_increment(&system_status_var::ha_read_last_count);
1432
ha_statistic_increment(&SSV::ha_read_last_count);
1125
1433
int error=mi_rlast(file, buf, active_index);
1126
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1434
table->status=error ? STATUS_NOT_FOUND: 0;
1178
1486
int ha_myisam::rnd_next(unsigned char *buf)
1180
ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
1488
ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1181
1489
int error=mi_scan(file, buf);
1182
getTable()->status=error ? STATUS_NOT_FOUND: 0;
1490
table->status=error ? STATUS_NOT_FOUND: 0;
1494
int ha_myisam::restart_rnd_next(unsigned char *buf, unsigned char *pos)
1496
return rnd_pos(buf,pos);
1186
1499
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;
1501
ha_statistic_increment(&SSV::ha_read_rnd_count);
1502
int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
1503
table->status=error ? STATUS_NOT_FOUND: 0;
1195
1508
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);
1510
my_off_t row_position= mi_position(file);
1511
my_store_ptr(ref, ref_length, row_position);
1201
1514
int ha_myisam::info(uint32_t flag)
1217
1530
if (flag & HA_STATUS_CONST)
1219
TableShare *share= getTable()->getMutableShare();
1532
TableShare *share= table->s;
1220
1533
stats.max_data_file_length= misam_info.max_data_file_length;
1221
1534
stats.max_index_file_length= misam_info.max_index_file_length;
1222
1535
stats.create_time= misam_info.create_time;
1223
1536
ref_length= misam_info.reflength;
1224
1537
share->db_options_in_use= misam_info.options;
1225
stats.block_size= myisam_key_cache_block_size; /* record block size */
1538
stats.block_size= 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;
1541
if (share->tmp_table == NO_TMP_TABLE)
1542
pthread_mutex_lock(&share->mutex);
1543
set_prefix(share->keys_in_use, share->keys);
1544
share->keys_in_use&= misam_info.key_map;
1273
1545
share->keys_for_keyread&= share->keys_in_use;
1274
1546
share->db_record_offset= misam_info.record_offset;
1275
1547
if (share->key_parts)
1276
memcpy(getTable()->key_info[0].rec_per_key,
1548
memcpy(table->key_info[0].rec_per_key,
1277
1549
misam_info.rec_per_key,
1278
sizeof(getTable()->key_info[0].rec_per_key)*share->key_parts);
1279
assert(share->getType() != message::Table::STANDARD);
1550
sizeof(table->key_info[0].rec_per_key)*share->key_parts);
1551
if (share->tmp_table == NO_TMP_TABLE)
1552
pthread_mutex_unlock(&share->mutex);
1282
1555
Set data_file_name and index_file_name to point at the symlink value
1283
1556
if table is symlinked (Ie; Real name is not same as generated name)
1285
1558
data_file_name= index_file_name= 0;
1286
internal::fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1559
fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1287
1560
MY_APPEND_EXT | MY_UNPACK_FILENAME);
1288
1561
if (strcmp(name_buff, misam_info.data_file_name))
1289
1562
data_file_name=misam_info.data_file_name;
1290
internal::fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1563
fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1291
1564
MY_APPEND_EXT | MY_UNPACK_FILENAME);
1292
1565
if (strcmp(name_buff, misam_info.index_file_name))
1293
1566
index_file_name=misam_info.index_file_name;
1328
1605
return mi_delete_all_rows(file);
1331
int MyisamEngine::doDropTable(Session &session,
1332
const TableIdentifier &identifier)
1608
int MyisamEngine::deleteTableImpl(Session*, const string table_name)
1334
session.getMessageCache().removeTableMessage(identifier);
1336
return mi_delete_table(identifier.getPath().c_str());
1610
return mi_delete_table(table_name.c_str());
1340
1614
int ha_myisam::external_lock(Session *session, int lock_type)
1342
1616
file->in_use= session;
1343
return mi_lock_database(file, !getTable()->getShare()->getType() ?
1617
return mi_lock_database(file, !table->s->tmp_table ?
1344
1618
lock_type : ((lock_type == F_UNLCK) ?
1345
1619
F_UNLCK : F_EXTRA_LCK));
1348
int MyisamEngine::doCreateTable(Session &session,
1350
const TableIdentifier &identifier,
1351
message::Table& create_proto)
1622
THR_LOCK_DATA **ha_myisam::store_lock(Session *,
1624
enum thr_lock_type lock_type)
1626
if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
1627
file->lock.type=lock_type;
1633
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
1635
ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
1636
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
1638
create_info->auto_increment_value= stats.auto_increment_value;
1640
create_info->data_file_name=data_file_name;
1641
create_info->index_file_name=index_file_name;
1645
int MyisamEngine::createTableImpl(Session *, const char *table_name,
1647
HA_CREATE_INFO *ha_create_info)
1354
1650
uint32_t create_flags= 0, create_records;
1356
1652
MI_KEYDEF *keydef;
1357
1653
MI_COLUMNDEF *recinfo;
1358
1654
MI_CREATE_INFO create_info;
1359
TableShare *share= table_arg.getMutableShare();
1655
TableShare *share= table_arg->s;
1360
1656
uint32_t options= share->db_options_in_use;
1361
if ((error= table2myisam(&table_arg, &keydef, &recinfo, &create_records)))
1657
if ((error= table2myisam(table_arg, &keydef, &recinfo, &create_records)))
1658
return(error); /* purecov: inspected */
1363
1659
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();
1660
create_info.max_rows= share->max_rows;
1661
create_info.reloc_rows= share->min_rows;
1366
1662
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 :
1663
create_info.auto_increment= (ha_create_info->auto_increment_value ?
1664
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;
1666
create_info.data_file_length= ((uint64_t) share->max_rows *
1667
share->avg_row_length);
1668
create_info.data_file_name= ha_create_info->data_file_name;
1669
create_info.index_file_name= ha_create_info->index_file_name;
1374
1670
create_info.language= share->table_charset->number;
1376
if (create_proto.type() == message::Table::TEMPORARY)
1672
if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
1377
1673
create_flags|= HA_CREATE_TMP_TABLE;
1674
if (ha_create_info->options & HA_CREATE_KEEP_FILES)
1675
create_flags|= HA_CREATE_KEEP_FILES;
1378
1676
if (options & HA_OPTION_PACK_RECORD)
1379
1677
create_flags|= HA_PACK_RECORD;
1678
if (options & HA_OPTION_CHECKSUM)
1679
create_flags|= HA_CREATE_CHECKSUM;
1680
if (options & HA_OPTION_DELAY_KEY_WRITE)
1681
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,
1683
/* TODO: Check that the following fn_format is really needed */
1684
error= mi_create(fn_format(buff, table_name, "", "",
1685
MY_UNPACK_FILENAME|MY_APPEND_EXT),
1686
share->keys, keydef,
1385
1687
create_records, recinfo,
1386
1688
0, (MI_UNIQUEDEF*) 0,
1387
1689
&create_info, create_flags);
1388
1690
free((unsigned char*) recinfo);
1390
session.getMessageCache().storeTableMessage(identifier, create_proto);
1396
int MyisamEngine::doRenameTable(Session &session, const TableIdentifier &from, const TableIdentifier &to)
1695
int MyisamEngine::renameTableImpl(Session*, const char *from, const char *to)
1398
session.getMessageCache().renameTableMessage(from, to);
1400
return mi_rename(from.getPath().c_str(), to.getPath().c_str());
1697
return mi_rename(from,to);
1423
1720
/* it's safe to call the following if bulk_insert isn't on */
1424
mi_flush_bulk_insert(file, getTable()->getShare()->next_number_index);
1721
mi_flush_bulk_insert(file, table->s->next_number_index);
1426
1723
(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),
1724
key_copy(key, table->record[0],
1725
table->key_info + table->s->next_number_index,
1726
table->s->next_number_key_offset);
1727
error= mi_rkey(file, table->record[1], (int) table->s->next_number_index,
1728
key, make_prev_keypart_map(table->s->next_number_keypart),
1432
1729
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);
1734
/* Get data from record[1] */
1735
nr= ((uint64_t) table->next_number_field->
1736
val_int_offset(table->s->rec_buff_length)+1);
1441
1738
extra(HA_EXTRA_NO_KEYREAD);
1442
1739
*first_value= nr;
1487
1784
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>()));
1787
static MyisamEngine *engine= NULL;
1789
static int myisam_init(PluginRegistry ®istry)
1791
engine= new MyisamEngine(engine_name);
1792
registry.add(engine);
1794
pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_FAST);
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
1799
int myisam_deinit(PluginRegistry ®istry)
1801
registry.remove(engine);
1804
pthread_mutex_destroy(&THR_LOCK_myisam);
1806
return mi_panic(HA_PANIC_CLOSE);
1810
/****************************************************************************
1811
* MyISAM MRR implementation: use DS-MRR
1812
***************************************************************************/
1814
int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
1815
uint32_t n_ranges, uint32_t mode,
1816
HANDLER_BUFFER *buf)
1818
return ds_mrr.dsmrr_init(this, &table->key_info[active_index],
1819
seq, seq_init_param, n_ranges, mode, buf);
1822
int ha_myisam::multi_range_read_next(char **range_info)
1824
return ds_mrr.dsmrr_next(this, range_info);
1827
ha_rows ha_myisam::multi_range_read_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
1828
void *seq_init_param,
1829
uint32_t n_ranges, uint32_t *bufsz,
1830
uint32_t *flags, COST_VECT *cost)
1833
This call is here because there is no location where this->table would
1835
TODO: consider moving it into some per-query initialization call.
1837
ds_mrr.init(this, table);
1838
return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz,
1842
int ha_myisam::multi_range_read_info(uint32_t keyno, uint32_t n_ranges, uint32_t keys,
1843
uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
1845
ds_mrr.init(this, table);
1846
return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
1849
/* MyISAM MRR implementation ends */
1852
/* Index condition pushdown implementation*/
1855
Item *ha_myisam::idx_cond_push(uint32_t keyno_arg, Item* idx_cond_arg)
1857
pushed_idx_cond_keyno= keyno_arg;
1858
pushed_idx_cond= idx_cond_arg;
1859
in_range_check_pushed_down= true;
1860
if (active_index == pushed_idx_cond_keyno)
1861
mi_set_index_cond_func(file, index_cond_func_myisam, this);
1865
static DRIZZLE_SYSVAR_UINT(block_size, block_size,
1866
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1867
N_("Block size to be used for MyISAM index pages."),
1868
NULL, NULL, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
1869
MI_MAX_KEY_BLOCK_LENGTH, 0);
1871
static DRIZZLE_SYSVAR_UINT(repair_threads, repair_threads,
1872
PLUGIN_VAR_RQCMDARG,
1873
N_("Number of threads to use when repairing MyISAM tables. The value of "
1874
"1 disables parallel repair."),
1875
NULL, NULL, 1, 1, UINT32_MAX, 0);
1877
static DRIZZLE_SYSVAR_ULONGLONG(max_sort_file_size, max_sort_file_size,
1878
PLUGIN_VAR_RQCMDARG,
1879
N_("Don't use the fast sort index method to created index if the temporary file would get bigger than this."),
1880
NULL, NULL, INT32_MAX, 0, UINT64_MAX, 0);
1882
static DRIZZLE_SYSVAR_ULONGLONG(sort_buffer_size, sort_buffer_size,
1883
PLUGIN_VAR_RQCMDARG,
1884
N_("The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE."),
1885
NULL, NULL, 8192*1024, 1024, SIZE_MAX, 0);
1887
extern uint32_t data_pointer_size;
1888
static DRIZZLE_SYSVAR_UINT(data_pointer_size, data_pointer_size,
1889
PLUGIN_VAR_RQCMDARG,
1890
N_("Default pointer size to be used for MyISAM tables."),
1891
NULL, NULL, 6, 2, 7, 0);
1893
static struct st_mysql_sys_var* system_variables[]= {
1894
DRIZZLE_SYSVAR(block_size),
1895
DRIZZLE_SYSVAR(repair_threads),
1896
DRIZZLE_SYSVAR(max_sort_file_size),
1897
DRIZZLE_SYSVAR(sort_buffer_size),
1898
DRIZZLE_SYSVAR(data_pointer_size),
1903
drizzle_declare_plugin(myisam)
1520
1908
"Default engine as of MySQL 3.23 with great performance",
1521
1909
PLUGIN_LICENSE_GPL,
1522
1910
myisam_init, /* Plugin Init */
1523
NULL, /* system variables */
1524
init_options /* config options */
1911
myisam_deinit, /* Plugin Deinit */
1912
NULL, /* status variables */
1913
system_variables, /* system variables */
1914
NULL /* config options */
1526
DRIZZLE_DECLARE_PLUGIN_END;
1916
drizzle_declare_plugin_end;