~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/myisam/ha_myisam.cc

  • Committer: Padraig O'Sullivan
  • Date: 2009-07-08 04:26:02 UTC
  • mto: (1089.3.4 merge)
  • mto: This revision was merged to the branch mainline in revision 1092.
  • Revision ID: osullivan.padraig@gmail.com-20090708042602-x4hmf9ny8dcpvb22
Replaced an instance where a uint8_t type was being used to hold a
collection of flags. Converted it to a std::bitset<2> instead.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 
16
16
 
17
17
 
18
 
#include "config.h"
19
 
#include "drizzled/internal/my_bit.h"
 
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/set_var.h"
32
 
#include <drizzled/plugin.h>
33
 
#include "drizzled/plugin/client.h"
34
 
#include "drizzled/table.h"
35
 
#include "drizzled/field/timestamp.h"
36
 
#include "drizzled/memory/multi_malloc.h"
37
 
#include "drizzled/plugin/daemon.h"
 
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/plugin/protocol.h>
 
29
#include <drizzled/table.h>
 
30
#include <drizzled/field/timestamp.h>
38
31
 
39
32
#include <string>
40
 
#include <sstream>
41
 
#include <map>
42
33
#include <algorithm>
43
34
 
44
35
using namespace std;
45
 
using namespace drizzled;
46
36
 
47
 
extern pthread_mutex_t LOCK_global_system_variables;
48
37
static const string engine_name("MyISAM");
49
38
 
 
39
ulong myisam_recover_options= HA_RECOVER_NONE;
50
40
pthread_mutex_t THR_LOCK_myisam= PTHREAD_MUTEX_INITIALIZER;
51
41
 
52
42
static uint32_t repair_threads;
53
 
static uint32_t myisam_key_cache_block_size;
54
 
static uint32_t myisam_key_cache_size;
55
 
static uint32_t myisam_key_cache_division_limit;
56
 
static uint32_t myisam_key_cache_age_threshold;
 
43
static uint32_t block_size;
57
44
static uint64_t max_sort_file_size;
58
45
static uint64_t sort_buffer_size;
59
46
 
 
47
/* bits in myisam_recover_options */
 
48
const char *myisam_recover_names[] =
 
49
{ "DEFAULT", "BACKUP", "FORCE", "QUICK", NULL};
 
50
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
 
51
                                 myisam_recover_names, NULL};
 
52
 
 
53
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
 
54
                                           "nulls_ignored", NULL};
 
55
TYPELIB myisam_stats_method_typelib= {
 
56
  array_elements(myisam_stats_method_names) - 1, "",
 
57
  myisam_stats_method_names, NULL};
 
58
 
 
59
 
60
60
/*****************************************************************************
61
61
** MyISAM tables
62
62
*****************************************************************************/
67
67
  NULL
68
68
};
69
69
 
70
 
class MyisamEngine : public plugin::StorageEngine
 
70
class MyisamEngine : public StorageEngine
71
71
{
72
 
  MyisamEngine();
73
 
  MyisamEngine(const MyisamEngine&);
74
 
  MyisamEngine& operator=(const MyisamEngine&);
75
72
public:
76
 
  explicit MyisamEngine(string name_arg) :
77
 
    plugin::StorageEngine(name_arg,
78
 
                          HTON_CAN_INDEX_BLOBS |
79
 
                          HTON_STATS_RECORDS_IS_EXACT |
80
 
                          HTON_TEMPORARY_ONLY |
81
 
                          HTON_NULL_IN_KEY |
82
 
                          HTON_HAS_RECORDS |
83
 
                          HTON_DUPLICATE_POS |
84
 
                          HTON_AUTO_PART_KEY |
85
 
                          HTON_SKIP_STORE_LOCK |
86
 
                          HTON_FILE_BASED )
87
 
  {
88
 
    pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_FAST);
89
 
  }
90
 
 
91
 
  virtual ~MyisamEngine()
92
 
  { 
93
 
    pthread_mutex_destroy(&THR_LOCK_myisam);
94
 
    end_key_cache(dflt_key_cache, 1);           // Can never fail
95
 
 
96
 
    mi_panic(HA_PANIC_CLOSE);
97
 
  }
98
 
 
99
 
  virtual Cursor *create(TableShare &table,
100
 
                         memory::Root *mem_root)
101
 
  {
102
 
    return new (mem_root) ha_myisam(*this, table);
 
73
  MyisamEngine(string name_arg)
 
74
   : StorageEngine(name_arg, HTON_CAN_RECREATE) {}
 
75
 
 
76
  virtual handler *create(TableShare *table,
 
77
                          MEM_ROOT *mem_root)
 
78
  {
 
79
    return new (mem_root) ha_myisam(this, table);
103
80
  }
104
81
 
105
82
  const char **bas_ext() const {
106
83
    return ha_myisam_exts;
107
84
  }
108
85
 
109
 
  int doCreateTable(Session&,
110
 
                    Table& table_arg,
111
 
                    drizzled::TableIdentifier &identifier,
112
 
                    message::Table&);
113
 
 
114
 
  int doRenameTable(Session&, TableIdentifier &from, TableIdentifier &to);
115
 
 
116
 
  int doDropTable(Session&, drizzled::TableIdentifier &identifier);
117
 
 
118
 
  int doGetTableDefinition(Session& session,
119
 
                           drizzled::TableIdentifier &identifier,
120
 
                           message::Table &table_message);
121
 
 
122
 
  /* Temp only engine, so do not return values. */
123
 
  void doGetTableNames(CachedDirectory &, SchemaIdentifier &, set<string>&) { };
124
 
 
125
 
  uint32_t max_supported_keys()          const { return MI_MAX_KEY; }
126
 
  uint32_t max_supported_key_length()    const { return MI_MAX_KEY_LENGTH; }
127
 
  uint32_t max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
128
 
 
129
 
  uint32_t index_flags(enum  ha_key_alg) const
130
 
  {
131
 
    return (HA_READ_NEXT |
132
 
            HA_READ_PREV |
133
 
            HA_READ_RANGE |
134
 
            HA_READ_ORDER |
135
 
            HA_KEYREAD_ONLY);
136
 
  }
137
 
  bool doDoesTableExist(Session& session, TableIdentifier &identifier);
138
 
 
139
 
  void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
140
 
                             drizzled::SchemaIdentifier &schema_identifier,
141
 
                             drizzled::TableIdentifiers &set_of_identifiers);
 
86
  int createTableImpl(Session *, const char *table_name,
 
87
                      Table *table_arg, HA_CREATE_INFO *ha_create_info);
 
88
 
 
89
  int renameTableImpl(Session*, const char *from, const char *to);
 
90
 
 
91
  int deleteTableImpl(Session*, const string table_name);
142
92
};
143
93
 
144
 
void MyisamEngine::doGetTableIdentifiers(drizzled::CachedDirectory&,
145
 
                                         drizzled::SchemaIdentifier&,
146
 
                                         drizzled::TableIdentifiers&)
147
 
{
148
 
}
149
 
 
150
 
bool MyisamEngine::doDoesTableExist(Session &session, TableIdentifier &identifier)
151
 
{
152
 
  return session.doesTableMessageExist(identifier);
153
 
}
154
 
 
155
 
int MyisamEngine::doGetTableDefinition(Session &session,
156
 
                                       drizzled::TableIdentifier &identifier,
157
 
                                       message::Table &table_message)
158
 
{
159
 
  if (session.getTableMessage(identifier, table_message))
160
 
    return EEXIST;
161
 
  return ENOENT;
162
 
}
163
 
 
164
 
/* 
165
 
  Convert to push_Warnings if you ever care about this, otherwise, it is a no-op.
166
 
*/
167
 
 
168
 
static void mi_check_print_msg(MI_CHECK *,      const char* ,
169
 
                               const char *, va_list )
170
 
{
 
94
// collect errors printed by mi_check routines
 
95
 
 
96
static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
 
97
                               const char *fmt, va_list args)
 
98
{
 
99
  Session* session = (Session*)param->session;
 
100
  Protocol *protocol= session->protocol;
 
101
  uint32_t length, msg_length;
 
102
  char msgbuf[MI_MAX_MSG_BUF];
 
103
  char name[NAME_LEN*2+2];
 
104
 
 
105
  msg_length= vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
 
106
  msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
 
107
 
 
108
  if (!session->protocol->isConnected())
 
109
  {
 
110
    errmsg_printf(ERRMSG_LVL_ERROR, "%s",msgbuf);
 
111
    return;
 
112
  }
 
113
 
 
114
  if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
 
115
                         T_AUTO_REPAIR))
 
116
  {
 
117
    my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
 
118
    return;
 
119
  }
 
120
  length= sprintf(name,"%s.%s",param->db_name,param->table_name);
 
121
 
 
122
  /*
 
123
    TODO: switch from protocol to push_warning here. The main reason we didn't
 
124
    it yet is parallel repair. Due to following trace:
 
125
    mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
 
126
 
 
127
    Also we likely need to lock mutex here (in both cases with protocol and
 
128
    push_warning).
 
129
  */
 
130
  protocol->prepareForResend();
 
131
  protocol->store(name, length);
 
132
  protocol->store(param->op_name);
 
133
  protocol->store(msg_type);
 
134
  protocol->store(msgbuf, msg_length);
 
135
  if (protocol->write())
 
136
    errmsg_printf(ERRMSG_LVL_ERROR, "Failed on drizzleclient_net_write, writing to stderr instead: %s\n",
 
137
                    msgbuf);
 
138
  return;
171
139
}
172
140
 
173
141
 
187
155
    table conformance in merge engine.
188
156
 
189
157
    The caller needs to free *recinfo_out after use. Since *recinfo_out
190
 
    and *keydef_out are allocated with a multi_malloc, *keydef_out
 
158
    and *keydef_out are allocated with a my_multi_malloc, *keydef_out
191
159
    is freed automatically when *recinfo_out is freed.
192
160
 
193
161
  RETURN VALUE
195
163
    !0 error code
196
164
*/
197
165
 
198
 
static int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
199
 
                        MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
 
166
int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
 
167
                 MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
200
168
{
201
169
  uint32_t i, j, recpos, minpos, fieldpos, temp_length, length;
202
170
  enum ha_base_keytype type= HA_KEYTYPE_BINARY;
207
175
  HA_KEYSEG *keyseg;
208
176
  TableShare *share= table_arg->s;
209
177
  uint32_t options= share->db_options_in_use;
210
 
  if (!(memory::multi_malloc(false,
 
178
  if (!(my_multi_malloc(MYF(MY_WME),
211
179
          recinfo_out, (share->fields * 2 + 2) * sizeof(MI_COLUMNDEF),
212
180
          keydef_out, share->keys * sizeof(MI_KEYDEF),
213
 
          &keyseg, (share->key_parts + share->keys) * sizeof(HA_KEYSEG),
 
181
          &keyseg,
 
182
          (share->key_parts + share->keys) * sizeof(HA_KEYSEG),
214
183
          NULL)))
215
 
    return(HA_ERR_OUT_OF_MEM);
 
184
    return(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
216
185
  keydef= *keydef_out;
217
186
  recinfo= *recinfo_out;
218
187
  pos= table_arg->key_info;
235
204
      {
236
205
        if (pos->key_part[j].length > 8 &&
237
206
            (type == HA_KEYTYPE_TEXT ||
 
207
             type == HA_KEYTYPE_NUM ||
238
208
             (type == HA_KEYTYPE_BINARY && !field->zero_pack())))
239
209
        {
240
210
          /* No blobs here */
340
310
  return(0);
341
311
}
342
312
 
343
 
int ha_myisam::reset_auto_increment(uint64_t value)
344
 
{
345
 
  file->s->state.auto_increment= value;
346
 
  return 0;
347
 
}
348
313
 
349
314
/*
350
315
  Check for underlying table conformance
386
351
      (should be corretly detected in table2myisam).
387
352
*/
388
353
 
389
 
static int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
390
 
                            uint32_t t1_keys, uint32_t t1_recs,
391
 
                            MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
392
 
                            uint32_t t2_keys, uint32_t t2_recs, bool strict)
 
354
int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
 
355
                     uint32_t t1_keys, uint32_t t1_recs,
 
356
                     MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
 
357
                     uint32_t t2_keys, uint32_t t2_recs, bool strict)
393
358
{
394
359
  uint32_t i, j;
395
360
  if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys))
424
389
      {
425
390
        if ((t1_keysegs_j__type == HA_KEYTYPE_VARTEXT2) &&
426
391
            (t2_keysegs[j].type == HA_KEYTYPE_VARTEXT1))
427
 
          t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1;
 
392
          t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1; /* purecov: tested */
428
393
        else if ((t1_keysegs_j__type == HA_KEYTYPE_VARBINARY2) &&
429
394
                 (t2_keysegs[j].type == HA_KEYTYPE_VARBINARY1))
430
 
          t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1;
 
395
          t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1; /* purecov: inspected */
431
396
      }
432
397
 
433
398
      if (t1_keysegs_j__type != t2_keysegs[j].type ||
461
426
}
462
427
 
463
428
 
 
429
extern "C" {
 
430
 
464
431
volatile int *killed_ptr(MI_CHECK *param)
465
432
{
466
433
  /* In theory Unsafe conversion, but should be ok for now */
532
499
  pthread_mutex_unlock(&file->s->intern_lock);
533
500
}
534
501
 
535
 
ha_myisam::ha_myisam(plugin::StorageEngine &engine_arg,
536
 
                     TableShare &table_arg)
537
 
  : Cursor(engine_arg, table_arg),
538
 
  file(0),
539
 
  can_enable_indexes(true),
540
 
  is_ordered(true)
541
 
{ }
542
 
 
543
 
Cursor *ha_myisam::clone(memory::Root *mem_root)
 
502
}
 
503
 
 
504
ha_myisam::ha_myisam(StorageEngine *engine_arg, TableShare *table_arg)
 
505
  :handler(engine_arg, table_arg), file(0),
 
506
  int_table_flags(HA_NULL_IN_KEY |
 
507
                  HA_DUPLICATE_POS |
 
508
                  HA_CAN_INDEX_BLOBS |
 
509
                  HA_AUTO_PART_KEY |
 
510
                  HA_FILE_BASED |
 
511
                  HA_NO_TRANSACTIONS |
 
512
                  HA_HAS_RECORDS |
 
513
                  HA_STATS_RECORDS_IS_EXACT |
 
514
                  HA_NEED_READ_RANGE_BUFFER |
 
515
                  HA_MRR_CANT_SORT),
 
516
   can_enable_indexes(1)
 
517
{}
 
518
 
 
519
handler *ha_myisam::clone(MEM_ROOT *mem_root)
544
520
{
545
 
  ha_myisam *new_handler= static_cast <ha_myisam *>(Cursor::clone(mem_root));
 
521
  ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(mem_root));
546
522
  if (new_handler)
547
523
    new_handler->file->state= file->state;
548
524
  return new_handler;
576
552
    open of a table that is in use by other threads already (if the
577
553
    MyISAM share exists already).
578
554
  */
579
 
  if (!(file=mi_open(name, mode, test_if_locked)))
580
 
    return (errno ? errno : -1);
581
 
 
 
555
  if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
 
556
    return (my_errno ? my_errno : -1);
582
557
  if (!table->s->tmp_table) /* No need to perform a check for tmp table */
583
558
  {
584
 
    if ((errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
 
559
    if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
585
560
    {
 
561
      /* purecov: begin inspected */
586
562
      goto err;
 
563
      /* purecov: end */
587
564
    }
588
565
    if (check_definition(keyinfo, recinfo, table->s->keys, recs,
589
566
                         file->s->keyinfo, file->s->rec,
590
567
                         file->s->base.keys, file->s->base.fields, true))
591
568
    {
592
 
      errno= HA_ERR_CRASHED;
 
569
      /* purecov: begin inspected */
 
570
      my_errno= HA_ERR_CRASHED;
593
571
      goto err;
 
572
      /* purecov: end */
594
573
    }
595
574
  }
596
575
 
601
580
  if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
602
581
    mi_extra(file, HA_EXTRA_WAIT_LOCK, 0);
603
582
  if (!table->s->db_record_offset)
604
 
    is_ordered= false;
605
 
 
 
583
    int_table_flags|=HA_REC_NOT_IN_SEQ;
 
584
  if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
 
585
    int_table_flags|=HA_HAS_CHECKSUM;
606
586
 
607
587
  keys_with_parts.reset();
608
588
  for (i= 0; i < table->s->keys; i++)
620
600
      }
621
601
    }
622
602
  }
623
 
  errno= 0;
 
603
  my_errno= 0;
624
604
  goto end;
625
605
 err:
626
606
  this->close();
627
607
 end:
628
608
  /*
629
 
    Both recinfo and keydef are allocated by multi_malloc(), thus only
 
609
    Both recinfo and keydef are allocated by my_multi_malloc(), thus only
630
610
    recinfo must be freed.
631
611
  */
632
612
  if (recinfo)
633
613
    free((unsigned char*) recinfo);
634
 
  return errno;
 
614
  return my_errno;
635
615
}
636
616
 
637
617
int ha_myisam::close(void)
643
623
 
644
624
int ha_myisam::write_row(unsigned char *buf)
645
625
{
646
 
  ha_statistic_increment(&system_status_var::ha_write_count);
 
626
  ha_statistic_increment(&SSV::ha_write_count);
647
627
 
648
628
  /*
649
629
    If we have an auto_increment column and we are writing a changed row
658
638
  return mi_write(file,buf);
659
639
}
660
640
 
 
641
int ha_myisam::check(Session* session, HA_CHECK_OPT* check_opt)
 
642
{
 
643
  if (!file) return HA_ADMIN_INTERNAL_ERROR;
 
644
  int error;
 
645
  MI_CHECK param;
 
646
  MYISAM_SHARE* share = file->s;
 
647
  const char *old_proc_info= session->get_proc_info();
 
648
 
 
649
  session->set_proc_info("Checking table");
 
650
  myisamchk_init(&param);
 
651
  param.session = session;
 
652
  param.op_name =   "check";
 
653
  param.db_name=    table->s->db.str;
 
654
  param.table_name= table->alias;
 
655
  param.testflag = check_opt->flags | T_CHECK | T_SILENT;
 
656
  param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
 
657
 
 
658
  if (!(table->db_stat & HA_READ_ONLY))
 
659
    param.testflag|= T_STATISTICS;
 
660
  param.using_global_keycache = 1;
 
661
 
 
662
  if (!mi_is_crashed(file) &&
 
663
      (((param.testflag & T_CHECK_ONLY_CHANGED) &&
 
664
        !(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
 
665
                                  STATE_CRASHED_ON_REPAIR)) &&
 
666
        share->state.open_count == 0) ||
 
667
       ((param.testflag & T_FAST) && (share->state.open_count ==
 
668
                                      (uint) (share->global_changed ? 1 : 0)))))
 
669
    return HA_ADMIN_ALREADY_DONE;
 
670
 
 
671
  error = chk_status(&param, file);             // Not fatal
 
672
  error = chk_size(&param, file);
 
673
  if (!error)
 
674
    error |= chk_del(&param, file, param.testflag);
 
675
  if (!error)
 
676
    error = chk_key(&param, file);
 
677
  if (!error)
 
678
  {
 
679
    if ((!(param.testflag & T_QUICK) &&
 
680
         ((share->options &
 
681
           (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
 
682
          (param.testflag & (T_EXTEND | T_MEDIUM)))) ||
 
683
        mi_is_crashed(file))
 
684
    {
 
685
      uint32_t old_testflag=param.testflag;
 
686
      param.testflag|=T_MEDIUM;
 
687
      if (!(error= init_io_cache(&param.read_cache, file->dfile,
 
688
                                 my_default_record_cache_size, READ_CACHE,
 
689
                                 share->pack.header_length, 1, MYF(MY_WME))))
 
690
      {
 
691
        error= chk_data_link(&param, file, param.testflag & T_EXTEND);
 
692
        end_io_cache(&(param.read_cache));
 
693
      }
 
694
      param.testflag= old_testflag;
 
695
    }
 
696
  }
 
697
  if (!error)
 
698
  {
 
699
    if ((share->state.changed & (STATE_CHANGED |
 
700
                                 STATE_CRASHED_ON_REPAIR |
 
701
                                 STATE_CRASHED | STATE_NOT_ANALYZED)) ||
 
702
        (param.testflag & T_STATISTICS) ||
 
703
        mi_is_crashed(file))
 
704
    {
 
705
      file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
 
706
      pthread_mutex_lock(&share->intern_lock);
 
707
      share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
 
708
                               STATE_CRASHED_ON_REPAIR);
 
709
      if (!(table->db_stat & HA_READ_ONLY))
 
710
        error=update_state_info(&param,file,UPDATE_TIME | UPDATE_OPEN_COUNT |
 
711
                                UPDATE_STAT);
 
712
      pthread_mutex_unlock(&share->intern_lock);
 
713
      info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
 
714
           HA_STATUS_CONST);
 
715
    }
 
716
  }
 
717
  else if (!mi_is_crashed(file) && !session->killed)
 
718
  {
 
719
    mi_mark_crashed(file);
 
720
    file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
 
721
  }
 
722
 
 
723
  session->set_proc_info(old_proc_info);
 
724
  return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
 
725
}
 
726
 
 
727
 
 
728
/*
 
729
  analyze the key distribution in the table
 
730
  As the table may be only locked for read, we have to take into account that
 
731
  two threads may do an analyze at the same time!
 
732
*/
 
733
 
 
734
int ha_myisam::analyze(Session *session,
 
735
                       HA_CHECK_OPT* )
 
736
{
 
737
  int error=0;
 
738
  MI_CHECK param;
 
739
  MYISAM_SHARE* share = file->s;
 
740
 
 
741
  myisamchk_init(&param);
 
742
  param.session = session;
 
743
  param.op_name=    "analyze";
 
744
  param.db_name=    table->s->db.str;
 
745
  param.table_name= table->alias;
 
746
  param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
 
747
                   T_DONT_CHECK_CHECKSUM);
 
748
  param.using_global_keycache = 1;
 
749
  param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
 
750
 
 
751
  if (!(share->state.changed & STATE_NOT_ANALYZED))
 
752
    return HA_ADMIN_ALREADY_DONE;
 
753
 
 
754
  error = chk_key(&param, file);
 
755
  if (!error)
 
756
  {
 
757
    pthread_mutex_lock(&share->intern_lock);
 
758
    error=update_state_info(&param,file,UPDATE_STAT);
 
759
    pthread_mutex_unlock(&share->intern_lock);
 
760
  }
 
761
  else if (!mi_is_crashed(file) && !session->killed)
 
762
    mi_mark_crashed(file);
 
763
  return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
 
764
}
 
765
 
 
766
 
 
767
int ha_myisam::repair(Session* session, HA_CHECK_OPT *check_opt)
 
768
{
 
769
  int error;
 
770
  MI_CHECK param;
 
771
  ha_rows start_records;
 
772
 
 
773
  if (!file) return HA_ADMIN_INTERNAL_ERROR;
 
774
 
 
775
  myisamchk_init(&param);
 
776
  param.session = session;
 
777
  param.op_name=  "repair";
 
778
  param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
 
779
                   T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
 
780
                   (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
 
781
  param.sort_buffer_length=  (size_t)sort_buffer_size;
 
782
 
 
783
  // Release latches since this can take a long time
 
784
  ha_release_temporary_latches(session);
 
785
 
 
786
  start_records=file->state->records;
 
787
  while ((error=repair(session,param,0)) && param.retry_repair)
 
788
  {
 
789
    param.retry_repair=0;
 
790
    if (test_all_bits(param.testflag,
 
791
                      (uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
 
792
    {
 
793
      param.testflag&= ~T_RETRY_WITHOUT_QUICK;
 
794
      errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' without quick",
 
795
                            table->s->path.str);
 
796
      continue;
 
797
    }
 
798
    param.testflag&= ~T_QUICK;
 
799
    if ((param.testflag & T_REP_BY_SORT))
 
800
    {
 
801
      param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
 
802
      errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' with keycache",
 
803
                            table->s->path.str);
 
804
      continue;
 
805
    }
 
806
    break;
 
807
  }
 
808
  if (!error && start_records != file->state->records &&
 
809
      !(check_opt->flags & T_VERY_SILENT))
 
810
  {
 
811
    char llbuff[22],llbuff2[22];
 
812
    errmsg_printf(ERRMSG_LVL_INFO, "Found %s of %s rows when repairing '%s'",
 
813
                          llstr(file->state->records, llbuff),
 
814
                          llstr(start_records, llbuff2),
 
815
                          table->s->path.str);
 
816
  }
 
817
  return error;
 
818
}
 
819
 
 
820
int ha_myisam::optimize(Session* session, HA_CHECK_OPT *check_opt)
 
821
{
 
822
  int error;
 
823
  if (!file) return HA_ADMIN_INTERNAL_ERROR;
 
824
  MI_CHECK param;
 
825
 
 
826
  myisamchk_init(&param);
 
827
  param.session = session;
 
828
  param.op_name= "optimize";
 
829
  param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
 
830
                   T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
 
831
  param.sort_buffer_length= (size_t)sort_buffer_size;
 
832
  if ((error= repair(session,param,1)) && param.retry_repair)
 
833
  {
 
834
    errmsg_printf(ERRMSG_LVL_WARN, "Warning: Optimize table got errno %d on %s.%s, retrying",
 
835
                      my_errno, param.db_name, param.table_name);
 
836
    param.testflag&= ~T_REP_BY_SORT;
 
837
    error= repair(session,param,1);
 
838
  }
 
839
  return error;
 
840
}
 
841
 
661
842
 
662
843
int ha_myisam::repair(Session *session, MI_CHECK &param, bool do_optimize)
663
844
{
685
866
    return(HA_ADMIN_FAILED);
686
867
  }
687
868
 
688
 
  param.db_name=    table->s->getSchemaName();
 
869
  param.db_name=    table->s->db.str;
689
870
  param.table_name= table->alias;
690
871
  param.tmpfile_createflag = O_RDWR | O_TRUNC;
691
872
  param.using_global_keycache = 1;
697
878
  // Don't lock tables if we have used LOCK Table
698
879
  if (mi_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK))
699
880
  {
700
 
    mi_check_print_error(&param,ER(ER_CANT_LOCK),errno);
 
881
    mi_check_print_error(&param,ER(ER_CANT_LOCK),my_errno);
701
882
    return(HA_ADMIN_FAILED);
702
883
  }
703
884
 
720
901
      {
721
902
        char buf[40];
722
903
        /* TODO: respect myisam_repair_threads variable */
723
 
        snprintf(buf, 40, "Repair with %d threads", internal::my_count_bits(key_map));
 
904
        snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
724
905
        session->set_proc_info(buf);
725
906
        error = mi_repair_parallel(&param, file, fixed_name,
726
907
            param.testflag & T_QUICK);
793
974
    {
794
975
      char llbuff[22],llbuff2[22];
795
976
      mi_check_print_warning(&param,"Number of rows changed from %s to %s",
796
 
                             internal::llstr(rows,llbuff),
797
 
                             internal::llstr(file->state->records,llbuff2));
 
977
                             llstr(rows,llbuff),
 
978
                             llstr(file->state->records,llbuff2));
798
979
    }
799
980
  }
800
981
  else
812
993
 
813
994
 
814
995
/*
 
996
  Assign table indexes to a specific key cache.
 
997
*/
 
998
 
 
999
int ha_myisam::assign_to_keycache(Session* session, HA_CHECK_OPT *check_opt)
 
1000
{
 
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;
 
1005
 
 
1006
  table->keys_in_use_for_query.reset();
 
1007
 
 
1008
  if (table_list->process_index_hints(table))
 
1009
    return(HA_ADMIN_FAILED);
 
1010
 
 
1011
  if ((error= mi_assign_to_key_cache(file, new_key_cache)))
 
1012
  {
 
1013
    char buf[STRING_BUFFER_USUAL_SIZE];
 
1014
    snprintf(buf, sizeof(buf),
 
1015
                "Failed to flush to index file (errno: %d)", error);
 
1016
    errmsg= buf;
 
1017
    error= HA_ADMIN_CORRUPT;
 
1018
  }
 
1019
 
 
1020
  if (error != HA_ADMIN_OK)
 
1021
  {
 
1022
    /* Send error to user */
 
1023
    MI_CHECK param;
 
1024
    myisamchk_init(&param);
 
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;
 
1029
    param.testflag= 0;
 
1030
    mi_check_print_error(&param, errmsg);
 
1031
  }
 
1032
  return(error);
 
1033
}
 
1034
 
 
1035
 
 
1036
/*
815
1037
  Disable indexes, making it persistent if requested.
816
1038
 
817
1039
  SYNOPSIS
870
1092
    Enable indexes, which might have been disabled by disable_index() before.
871
1093
    The modes without _SAVE work only if both data and indexes are empty,
872
1094
    since the MyISAM repair would enable them persistently.
873
 
    To be sure in these cases, call Cursor::delete_all_rows() before.
 
1095
    To be sure in these cases, call handler::delete_all_rows() before.
874
1096
 
875
1097
  IMPLEMENTATION
876
1098
    HA_KEY_SWITCH_NONUNIQ       is not implemented.
914
1136
                     T_CREATE_MISSING_KEYS);
915
1137
    param.myf_rw&= ~MY_WAIT_IF_FULL;
916
1138
    param.sort_buffer_length=  (size_t)sort_buffer_size;
917
 
    param.stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
 
1139
    param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
918
1140
    if ((error= (repair(session,param,0) != HA_ADMIN_OK)) && param.retry_repair)
919
1141
    {
920
1142
      errmsg_printf(ERRMSG_LVL_WARN, "Warning: Enabling keys got errno %d on %s.%s, retrying",
921
 
                        errno, param.db_name, param.table_name);
 
1143
                        my_errno, param.db_name, param.table_name);
922
1144
      /* Repairing by sort failed. Now try standard repair method. */
923
1145
      param.testflag&= ~(T_REP_BY_SORT | T_QUICK);
924
1146
      error= (repair(session,param,0) != HA_ADMIN_OK);
981
1203
void ha_myisam::start_bulk_insert(ha_rows rows)
982
1204
{
983
1205
  Session *session= current_session;
984
 
  ulong size= session->variables.read_buff_size;
 
1206
  ulong size= min(session->variables.read_buff_size,
 
1207
                  (uint32_t)(table->s->avg_row_length*rows));
985
1208
 
986
1209
  /* don't enable row cache if too few rows */
987
1210
  if (! rows || (rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE))
1007
1230
                          (size_t)session->variables.bulk_insert_buff_size,
1008
1231
                          rows);
1009
1232
    }
 
1233
 
 
1234
  return;
1010
1235
}
1011
1236
 
1012
1237
/*
1032
1257
 
1033
1258
 
1034
1259
 
 
1260
bool ha_myisam::is_crashed() const
 
1261
{
 
1262
  return (file->s->state.changed & STATE_CRASHED ||
 
1263
          (file->s->state.open_count));
 
1264
}
 
1265
 
1035
1266
int ha_myisam::update_row(const unsigned char *old_data, unsigned char *new_data)
1036
1267
{
1037
 
  ha_statistic_increment(&system_status_var::ha_update_count);
 
1268
  ha_statistic_increment(&SSV::ha_update_count);
1038
1269
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
1039
1270
    table->timestamp_field->set_time();
1040
1271
  return mi_update(file,old_data,new_data);
1042
1273
 
1043
1274
int ha_myisam::delete_row(const unsigned char *buf)
1044
1275
{
1045
 
  ha_statistic_increment(&system_status_var::ha_delete_count);
 
1276
  ha_statistic_increment(&SSV::ha_delete_count);
1046
1277
  return mi_delete(file,buf);
1047
1278
}
1048
1279
 
 
1280
#ifdef __cplusplus
 
1281
extern "C" {
 
1282
#endif
 
1283
 
 
1284
bool index_cond_func_myisam(void *arg)
 
1285
{
 
1286
  ha_myisam *h= (ha_myisam*)arg;
 
1287
  /*if (h->in_range_read)*/
 
1288
  if (h->end_range)
 
1289
  {
 
1290
    if (h->compare_key2(h->end_range) > 0)
 
1291
      return 2; /* caller should return HA_ERR_END_OF_FILE already */
 
1292
  }
 
1293
  return (bool)h->pushed_idx_cond->val_int();
 
1294
}
 
1295
 
 
1296
#ifdef __cplusplus
 
1297
}
 
1298
#endif
 
1299
 
1049
1300
 
1050
1301
int ha_myisam::index_init(uint32_t idx, bool )
1051
1302
{
1052
1303
  active_index=idx;
1053
1304
  //in_range_read= false;
 
1305
  if (pushed_idx_cond_keyno == idx)
 
1306
    mi_set_index_cond_func(file, index_cond_func_myisam, this);
1054
1307
  return 0;
1055
1308
}
1056
1309
 
1058
1311
int ha_myisam::index_end()
1059
1312
{
1060
1313
  active_index=MAX_KEY;
 
1314
  //pushed_idx_cond_keyno= MAX_KEY;
 
1315
  mi_set_index_cond_func(file, NULL, 0);
 
1316
  in_range_check_pushed_down= false;
 
1317
  ds_mrr.dsmrr_close();
1061
1318
  return 0;
1062
1319
}
1063
1320
 
1064
1321
 
 
1322
uint32_t ha_myisam::index_flags(uint32_t inx, uint32_t, bool) const
 
1323
{
 
1324
  return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ?
 
1325
          0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
 
1326
          HA_READ_ORDER | HA_KEYREAD_ONLY |
 
1327
          (keys_with_parts.test(inx)?0:HA_DO_INDEX_COND_PUSHDOWN));
 
1328
}
 
1329
 
 
1330
 
1065
1331
int ha_myisam::index_read_map(unsigned char *buf, const unsigned char *key,
1066
1332
                              key_part_map keypart_map,
1067
1333
                              enum ha_rkey_function find_flag)
1068
1334
{
1069
1335
  assert(inited==INDEX);
1070
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
1336
  ha_statistic_increment(&SSV::ha_read_key_count);
1071
1337
  int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
1072
1338
  table->status=error ? STATUS_NOT_FOUND: 0;
1073
1339
  return error;
1077
1343
                                  key_part_map keypart_map,
1078
1344
                                  enum ha_rkey_function find_flag)
1079
1345
{
1080
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
1346
  ha_statistic_increment(&SSV::ha_read_key_count);
1081
1347
  int error=mi_rkey(file, buf, index, key, keypart_map, find_flag);
1082
1348
  table->status=error ? STATUS_NOT_FOUND: 0;
1083
1349
  return error;
1087
1353
                                   key_part_map keypart_map)
1088
1354
{
1089
1355
  assert(inited==INDEX);
1090
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
1356
  ha_statistic_increment(&SSV::ha_read_key_count);
1091
1357
  int error=mi_rkey(file, buf, active_index, key, keypart_map,
1092
1358
                    HA_READ_PREFIX_LAST);
1093
1359
  table->status=error ? STATUS_NOT_FOUND: 0;
1097
1363
int ha_myisam::index_next(unsigned char *buf)
1098
1364
{
1099
1365
  assert(inited==INDEX);
1100
 
  ha_statistic_increment(&system_status_var::ha_read_next_count);
 
1366
  ha_statistic_increment(&SSV::ha_read_next_count);
1101
1367
  int error=mi_rnext(file,buf,active_index);
1102
1368
  table->status=error ? STATUS_NOT_FOUND: 0;
1103
1369
  return error;
1106
1372
int ha_myisam::index_prev(unsigned char *buf)
1107
1373
{
1108
1374
  assert(inited==INDEX);
1109
 
  ha_statistic_increment(&system_status_var::ha_read_prev_count);
 
1375
  ha_statistic_increment(&SSV::ha_read_prev_count);
1110
1376
  int error=mi_rprev(file,buf, active_index);
1111
1377
  table->status=error ? STATUS_NOT_FOUND: 0;
1112
1378
  return error;
1115
1381
int ha_myisam::index_first(unsigned char *buf)
1116
1382
{
1117
1383
  assert(inited==INDEX);
1118
 
  ha_statistic_increment(&system_status_var::ha_read_first_count);
 
1384
  ha_statistic_increment(&SSV::ha_read_first_count);
1119
1385
  int error=mi_rfirst(file, buf, active_index);
1120
1386
  table->status=error ? STATUS_NOT_FOUND: 0;
1121
1387
  return error;
1124
1390
int ha_myisam::index_last(unsigned char *buf)
1125
1391
{
1126
1392
  assert(inited==INDEX);
1127
 
  ha_statistic_increment(&system_status_var::ha_read_last_count);
 
1393
  ha_statistic_increment(&SSV::ha_read_last_count);
1128
1394
  int error=mi_rlast(file, buf, active_index);
1129
1395
  table->status=error ? STATUS_NOT_FOUND: 0;
1130
1396
  return error;
1136
1402
{
1137
1403
  int error;
1138
1404
  assert(inited==INDEX);
1139
 
  ha_statistic_increment(&system_status_var::ha_read_next_count);
 
1405
  ha_statistic_increment(&SSV::ha_read_next_count);
1140
1406
  do
1141
1407
  {
1142
1408
    error= mi_rnext_same(file,buf);
1154
1420
  //if (!eq_range_arg)
1155
1421
  //  in_range_read= true;
1156
1422
 
1157
 
  res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
 
1423
  res= handler::read_range_first(start_key, end_key, eq_range_arg, sorted);
1158
1424
 
1159
1425
  //if (res)
1160
1426
  //  in_range_read= false;
1164
1430
 
1165
1431
int ha_myisam::read_range_next()
1166
1432
{
1167
 
  int res= Cursor::read_range_next();
 
1433
  int res= handler::read_range_next();
1168
1434
  //if (res)
1169
1435
  //  in_range_read= false;
1170
1436
  return res;
1180
1446
 
1181
1447
int ha_myisam::rnd_next(unsigned char *buf)
1182
1448
{
1183
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
 
1449
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1184
1450
  int error=mi_scan(file, buf);
1185
1451
  table->status=error ? STATUS_NOT_FOUND: 0;
1186
1452
  return error;
1193
1459
 
1194
1460
int ha_myisam::rnd_pos(unsigned char *buf, unsigned char *pos)
1195
1461
{
1196
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_count);
1197
 
  int error=mi_rrnd(file, buf, internal::my_get_ptr(pos,ref_length));
 
1462
  ha_statistic_increment(&SSV::ha_read_rnd_count);
 
1463
  int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
1198
1464
  table->status=error ? STATUS_NOT_FOUND: 0;
1199
1465
  return error;
1200
1466
}
1202
1468
 
1203
1469
void ha_myisam::position(const unsigned char *)
1204
1470
{
1205
 
  internal::my_off_t row_position= mi_position(file);
1206
 
  internal::my_store_ptr(ref, ref_length, row_position);
 
1471
  my_off_t row_position= mi_position(file);
 
1472
  my_store_ptr(ref, ref_length, row_position);
1207
1473
}
1208
1474
 
1209
1475
int ha_myisam::info(uint32_t flag)
1230
1496
    stats.create_time= misam_info.create_time;
1231
1497
    ref_length= misam_info.reflength;
1232
1498
    share->db_options_in_use= misam_info.options;
1233
 
    stats.block_size= myisam_key_cache_block_size;        /* record block size */
 
1499
    stats.block_size= block_size;        /* record block size */
1234
1500
 
1235
1501
    /* Update share */
1236
 
    if (share->tmp_table == message::Table::STANDARD)
 
1502
    if (share->tmp_table == NO_TMP_TABLE)
1237
1503
      pthread_mutex_lock(&share->mutex);
1238
1504
    set_prefix(share->keys_in_use, share->keys);
1239
 
    /*
1240
 
     * Due to bug 394932 (32-bit solaris build failure), we need
1241
 
     * to convert the uint64_t key_map member of the misam_info
1242
 
     * structure in to a std::bitset so that we can logically and
1243
 
     * it with the share->key_in_use key_map.
1244
 
     */
1245
 
    ostringstream ostr;
1246
 
    string binary_key_map;
1247
 
    uint64_t num= misam_info.key_map;
1248
 
    /*
1249
 
     * Convert the uint64_t to a binary
1250
 
     * string representation of it.
1251
 
     */
1252
 
    while (num > 0)
1253
 
    {
1254
 
      uint64_t bin_digit= num % 2;
1255
 
      ostr << bin_digit;
1256
 
      num/= 2;
1257
 
    }
1258
 
    binary_key_map.append(ostr.str());
1259
 
    /*
1260
 
     * Now we have the binary string representation of the
1261
 
     * flags, we need to fill that string representation out
1262
 
     * with the appropriate number of bits. This is needed
1263
 
     * since key_map is declared as a std::bitset of a certain bit
1264
 
     * width that depends on the MAX_INDEXES variable. 
1265
 
     */
1266
 
    if (MAX_INDEXES <= 64)
1267
 
    {
1268
 
      size_t len= 72 - binary_key_map.length();
1269
 
      string all_zeros(len, '0');
1270
 
      binary_key_map.insert(binary_key_map.begin(),
1271
 
                            all_zeros.begin(),
1272
 
                            all_zeros.end());
1273
 
    }
1274
 
    else
1275
 
    {
1276
 
      size_t len= (MAX_INDEXES + 7) / 8 * 8;
1277
 
      string all_zeros(len, '0');
1278
 
      binary_key_map.insert(binary_key_map.begin(),
1279
 
                            all_zeros.begin(),
1280
 
                            all_zeros.end());
1281
 
    }
1282
 
    key_map tmp_map(binary_key_map);
1283
 
    share->keys_in_use&= tmp_map;
 
1505
    share->keys_in_use&= misam_info.key_map;
1284
1506
    share->keys_for_keyread&= share->keys_in_use;
1285
1507
    share->db_record_offset= misam_info.record_offset;
1286
1508
    if (share->key_parts)
1287
1509
      memcpy(table->key_info[0].rec_per_key,
1288
1510
             misam_info.rec_per_key,
1289
1511
             sizeof(table->key_info[0].rec_per_key)*share->key_parts);
1290
 
    if (share->tmp_table == message::Table::STANDARD)
 
1512
    if (share->tmp_table == NO_TMP_TABLE)
1291
1513
      pthread_mutex_unlock(&share->mutex);
1292
1514
 
1293
1515
   /*
1295
1517
     if table is symlinked (Ie;  Real name is not same as generated name)
1296
1518
   */
1297
1519
    data_file_name= index_file_name= 0;
1298
 
    internal::fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
 
1520
    fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1299
1521
              MY_APPEND_EXT | MY_UNPACK_FILENAME);
1300
1522
    if (strcmp(name_buff, misam_info.data_file_name))
1301
1523
      data_file_name=misam_info.data_file_name;
1302
 
    internal::fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
 
1524
    fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1303
1525
              MY_APPEND_EXT | MY_UNPACK_FILENAME);
1304
1526
    if (strcmp(name_buff, misam_info.index_file_name))
1305
1527
      index_file_name=misam_info.index_file_name;
1307
1529
  if (flag & HA_STATUS_ERRKEY)
1308
1530
  {
1309
1531
    errkey  = misam_info.errkey;
1310
 
    internal::my_store_ptr(dup_ref, ref_length, misam_info.dupp_key_pos);
 
1532
    my_store_ptr(dup_ref, ref_length, misam_info.dupp_key_pos);
1311
1533
  }
1312
1534
  if (flag & HA_STATUS_TIME)
1313
1535
    stats.update_time = misam_info.update_time;
1325
1547
 
1326
1548
int ha_myisam::reset(void)
1327
1549
{
 
1550
  pushed_idx_cond= NULL;
 
1551
  pushed_idx_cond_keyno= MAX_KEY;
 
1552
  mi_set_index_cond_func(file, NULL, 0);
 
1553
  ds_mrr.dsmrr_close();
1328
1554
  return mi_reset(file);
1329
1555
}
1330
1556
 
1340
1566
  return mi_delete_all_rows(file);
1341
1567
}
1342
1568
 
1343
 
int MyisamEngine::doDropTable(Session &session,
1344
 
                              drizzled::TableIdentifier &identifier)
 
1569
int MyisamEngine::deleteTableImpl(Session*, const string table_name)
1345
1570
{
1346
 
  session.removeTableMessage(identifier);
1347
 
 
1348
 
  return mi_delete_table(identifier.getPath().c_str());
 
1571
  return mi_delete_table(table_name.c_str());
1349
1572
}
1350
1573
 
1351
1574
 
1357
1580
                                       F_UNLCK : F_EXTRA_LCK));
1358
1581
}
1359
1582
 
1360
 
int MyisamEngine::doCreateTable(Session &session,
1361
 
                                Table& table_arg,
1362
 
                                drizzled::TableIdentifier &identifier,
1363
 
                                message::Table& create_proto)
 
1583
THR_LOCK_DATA **ha_myisam::store_lock(Session *,
 
1584
                                      THR_LOCK_DATA **to,
 
1585
                                      enum thr_lock_type lock_type)
 
1586
{
 
1587
  if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
 
1588
    file->lock.type=lock_type;
 
1589
  *to++= &file->lock;
 
1590
 
 
1591
  return to;
 
1592
}
 
1593
 
 
1594
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
 
1595
{
 
1596
  ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
 
1597
  if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
 
1598
  {
 
1599
    create_info->auto_increment_value= stats.auto_increment_value;
 
1600
  }
 
1601
  create_info->data_file_name=data_file_name;
 
1602
  create_info->index_file_name=index_file_name;
 
1603
}
 
1604
 
 
1605
 
 
1606
int MyisamEngine::createTableImpl(Session *, const char *table_name,
 
1607
                                  Table *table_arg,
 
1608
                                  HA_CREATE_INFO *ha_create_info)
1364
1609
{
1365
1610
  int error;
1366
1611
  uint32_t create_flags= 0, create_records;
1368
1613
  MI_KEYDEF *keydef;
1369
1614
  MI_COLUMNDEF *recinfo;
1370
1615
  MI_CREATE_INFO create_info;
1371
 
  TableShare *share= table_arg.s;
 
1616
  TableShare *share= table_arg->s;
1372
1617
  uint32_t options= share->db_options_in_use;
1373
 
  if ((error= table2myisam(&table_arg, &keydef, &recinfo, &create_records)))
1374
 
    return(error);
 
1618
  if ((error= table2myisam(table_arg, &keydef, &recinfo, &create_records)))
 
1619
    return(error); /* purecov: inspected */
1375
1620
  memset(&create_info, 0, sizeof(create_info));
1376
 
  create_info.max_rows= create_proto.options().max_rows();
1377
 
  create_info.reloc_rows= create_proto.options().min_rows();
 
1621
  create_info.max_rows= share->max_rows;
 
1622
  create_info.reloc_rows= share->min_rows;
1378
1623
  create_info.with_auto_increment= share->next_number_key_offset == 0;
1379
 
  create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
1380
 
                               create_proto.options().auto_increment_value() -1 :
 
1624
  create_info.auto_increment= (ha_create_info->auto_increment_value ?
 
1625
                               ha_create_info->auto_increment_value -1 :
1381
1626
                               (uint64_t) 0);
1382
 
  create_info.data_file_length= (create_proto.options().max_rows() *
1383
 
                                 create_proto.options().avg_row_length());
1384
 
  create_info.data_file_name= NULL;
1385
 
  create_info.index_file_name=  NULL;
 
1627
  create_info.data_file_length= ((uint64_t) share->max_rows *
 
1628
                                 share->avg_row_length);
 
1629
  create_info.data_file_name= ha_create_info->data_file_name;
 
1630
  create_info.index_file_name= ha_create_info->index_file_name;
1386
1631
  create_info.language= share->table_charset->number;
1387
1632
 
1388
 
  if (create_proto.type() == message::Table::TEMPORARY)
 
1633
  if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
1389
1634
    create_flags|= HA_CREATE_TMP_TABLE;
 
1635
  if (ha_create_info->options & HA_CREATE_KEEP_FILES)
 
1636
    create_flags|= HA_CREATE_KEEP_FILES;
1390
1637
  if (options & HA_OPTION_PACK_RECORD)
1391
1638
    create_flags|= HA_PACK_RECORD;
 
1639
  if (options & HA_OPTION_CHECKSUM)
 
1640
    create_flags|= HA_CREATE_CHECKSUM;
 
1641
  if (options & HA_OPTION_DELAY_KEY_WRITE)
 
1642
    create_flags|= HA_CREATE_DELAY_KEY_WRITE;
1392
1643
 
1393
 
  /* TODO: Check that the following internal::fn_format is really needed */
1394
 
  error= mi_create(internal::fn_format(buff, identifier.getPath().c_str(), "", "",
1395
 
                                       MY_UNPACK_FILENAME|MY_APPEND_EXT),
 
1644
  /* TODO: Check that the following fn_format is really needed */
 
1645
  error= mi_create(fn_format(buff, table_name, "", "",
 
1646
                             MY_UNPACK_FILENAME|MY_APPEND_EXT),
1396
1647
                   share->keys, keydef,
1397
1648
                   create_records, recinfo,
1398
1649
                   0, (MI_UNIQUEDEF*) 0,
1399
1650
                   &create_info, create_flags);
1400
1651
  free((unsigned char*) recinfo);
1401
 
 
1402
 
  session.storeTableMessage(identifier, create_proto);
1403
 
 
1404
 
  return error;
 
1652
  return(error);
1405
1653
}
1406
1654
 
1407
1655
 
1408
 
int MyisamEngine::doRenameTable(Session &session, TableIdentifier &from, TableIdentifier &to)
 
1656
int MyisamEngine::renameTableImpl(Session*, const char *from, const char *to)
1409
1657
{
1410
 
  session.renameTableMessage(from, to);
1411
 
 
1412
 
  return mi_rename(from.getPath().c_str(), to.getPath().c_str());
 
1658
  return mi_rename(from,to);
1413
1659
}
1414
1660
 
1415
1661
 
1501
1747
 
1502
1748
static MyisamEngine *engine= NULL;
1503
1749
 
1504
 
static int myisam_init(plugin::Context &context)
 
1750
static int myisam_init(PluginRegistry &registry)
1505
1751
{
1506
1752
  engine= new MyisamEngine(engine_name);
1507
 
  context.add(engine);
1508
 
 
1509
 
  /* call ha_init_key_cache() on all key caches to init them */
1510
 
  int error= init_key_cache(dflt_key_cache,
1511
 
                            myisam_key_cache_block_size,
1512
 
                            myisam_key_cache_size,
1513
 
                            myisam_key_cache_division_limit, 
1514
 
                            myisam_key_cache_age_threshold);
1515
 
 
1516
 
  if (error == 0)
1517
 
    exit(1); /* Memory Allocation Failure */
 
1753
  registry.add(engine);
 
1754
 
 
1755
  pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_FAST);
1518
1756
 
1519
1757
  return 0;
1520
1758
}
1521
1759
 
1522
 
 
1523
 
static void sys_var_key_cache_size_update(Session *session, drizzle_sys_var *var, void *, const void *save)
1524
 
{
1525
 
  uint32_t tmp= *static_cast<const uint32_t *>(save);
1526
 
  bool error= 0;
1527
 
 
1528
 
        struct option option_limits;
1529
 
  plugin_opt_set_limits(&option_limits, var);
1530
 
        option_limits.name= "myisam_key_cache_size";
1531
 
 
1532
 
  if (dflt_key_cache->in_init)
1533
 
    return;
1534
 
 
1535
 
  myisam_key_cache_size= static_cast<uint32_t>(fix_unsigned(session, static_cast<uint64_t>(tmp), &option_limits));
1536
 
 
1537
 
  /* If key cache didn't existed initialize it, else resize it */
1538
 
  dflt_key_cache->in_init= 1;
1539
 
 
1540
 
  error= ! resize_key_cache(dflt_key_cache,
1541
 
                                                                                                                myisam_key_cache_block_size,
1542
 
                            myisam_key_cache_size,
1543
 
                            myisam_key_cache_division_limit,
1544
 
                                                                                                          myisam_key_cache_age_threshold);
1545
 
  dflt_key_cache->in_init= 0;
1546
 
}
1547
 
 
1548
 
static void sys_var_key_cache_block_size_update(Session *session, drizzle_sys_var *var, void *, const void *save)
1549
 
{
1550
 
  uint32_t tmp= *static_cast<const uint32_t *>(save);
1551
 
  bool error= 0;
1552
 
 
1553
 
        struct option option_limits;
1554
 
  plugin_opt_set_limits(&option_limits, var);
1555
 
        option_limits.name= "myisam_key_cache_block_size";
1556
 
 
1557
 
  if (dflt_key_cache->in_init)
1558
 
    return;
1559
 
 
1560
 
  myisam_key_cache_block_size= static_cast<uint32_t>(fix_unsigned(session, static_cast<uint64_t>(tmp), &option_limits));
1561
 
 
1562
 
  dflt_key_cache->in_init= 1;
1563
 
 
1564
 
  error= ! resize_key_cache(dflt_key_cache,
1565
 
                                                                                                                myisam_key_cache_block_size,
1566
 
                            myisam_key_cache_size,
1567
 
                            myisam_key_cache_division_limit,
1568
 
                                                                                                          myisam_key_cache_age_threshold);
1569
 
 
1570
 
  dflt_key_cache->in_init= 0;
1571
 
}
1572
 
 
1573
 
static void sys_var_key_cache_division_limit_update(Session *session, drizzle_sys_var *var, void *, const void *save)
1574
 
{
1575
 
  uint32_t tmp= *static_cast<const uint32_t *>(save);
1576
 
  bool error= 0;
1577
 
 
1578
 
        struct option option_limits;
1579
 
  plugin_opt_set_limits(&option_limits, var);
1580
 
        option_limits.name= "myisam_key_cache_division_limit";
1581
 
 
1582
 
  if (dflt_key_cache->in_init)
1583
 
    return;
1584
 
 
1585
 
  myisam_key_cache_division_limit= static_cast<uint32_t>(fix_unsigned(session, static_cast<uint64_t>(tmp), &option_limits));
1586
 
 
1587
 
  dflt_key_cache->in_init= 1;
1588
 
 
1589
 
  error= ! resize_key_cache(dflt_key_cache,
1590
 
                                                                                                                myisam_key_cache_block_size,
1591
 
                            myisam_key_cache_size,
1592
 
                            myisam_key_cache_division_limit,
1593
 
                                                                                                          myisam_key_cache_age_threshold);
1594
 
 
1595
 
  dflt_key_cache->in_init= 0;
1596
 
}
1597
 
 
1598
 
static void sys_var_key_cache_age_threshold_update(Session *session, drizzle_sys_var *var, void *, const void *save)
1599
 
{
1600
 
  uint32_t tmp= *static_cast<const uint32_t *>(save);
1601
 
  bool error= 0;
1602
 
 
1603
 
        struct option option_limits;
1604
 
  plugin_opt_set_limits(&option_limits, var);
1605
 
        option_limits.name= "myisam_key_cache_age_threshold";
1606
 
 
1607
 
  if (dflt_key_cache->in_init)
1608
 
    return;
1609
 
 
1610
 
  myisam_key_cache_age_threshold= static_cast<uint32_t>(fix_unsigned(session, static_cast<uint64_t>(tmp), &option_limits));
1611
 
 
1612
 
  dflt_key_cache->in_init= 1;
1613
 
 
1614
 
  error= ! resize_key_cache(dflt_key_cache,
1615
 
                                                                                                                myisam_key_cache_block_size,
1616
 
                            myisam_key_cache_size,
1617
 
                            myisam_key_cache_division_limit,
1618
 
                                                                                                          myisam_key_cache_age_threshold);
1619
 
 
1620
 
  dflt_key_cache->in_init= 0;
1621
 
}
1622
 
 
1623
 
static DRIZZLE_SYSVAR_UINT(key_cache_block_size,
1624
 
                            myisam_key_cache_block_size,
1625
 
                            PLUGIN_VAR_RQCMDARG,
1626
 
                            N_("Block size to be used for MyISAM index pages."),
1627
 
                            NULL,
1628
 
                            sys_var_key_cache_block_size_update,
1629
 
                            KEY_CACHE_BLOCK_SIZE,
1630
 
                            512, 
1631
 
                            16 * 1024,
1632
 
                            0);
1633
 
 
1634
 
static DRIZZLE_SYSVAR_UINT(key_cache_age_threshold, myisam_key_cache_age_threshold,
1635
 
                            PLUGIN_VAR_RQCMDARG,
1636
 
                            N_("This characterizes the number of hits a hot block has to be untouched "
1637
 
                            "until it is considered aged enough to be downgraded to a warm block. "
1638
 
                            "This specifies the percentage ratio of that number of hits to the "
1639
 
                            "total number of blocks in key cache"),
1640
 
                            NULL,
1641
 
                            sys_var_key_cache_age_threshold_update,
1642
 
                            300,
1643
 
                            100, 
1644
 
                            UINT32_MAX,
1645
 
                            0);
1646
 
 
1647
 
static DRIZZLE_SYSVAR_UINT(key_cache_division_limit, myisam_key_cache_division_limit,
1648
 
                            PLUGIN_VAR_RQCMDARG,
1649
 
                            N_("The minimum percentage of warm blocks in key cache"),
1650
 
                            NULL,
1651
 
                            sys_var_key_cache_division_limit_update,
1652
 
                            100,
1653
 
                            1, 
1654
 
                            100,
1655
 
                            0);
1656
 
 
1657
 
static DRIZZLE_SYSVAR_UINT(key_cache_size,
1658
 
                            myisam_key_cache_size,
1659
 
                            PLUGIN_VAR_RQCMDARG,
1660
 
                            N_("The size of the buffer used for index blocks for MyISAM tables. "
1661
 
                            "Increase this to get better index handling (for all reads and multiple "
1662
 
                            "writes) to as much as you can afford;"),
1663
 
                            NULL,
1664
 
                            sys_var_key_cache_size_update,
1665
 
                            KEY_CACHE_SIZE,
1666
 
                            1 * 1024 * 1024, 
1667
 
                            UINT32_MAX,
1668
 
                            IO_SIZE);
 
1760
int myisam_deinit(PluginRegistry &registry)
 
1761
{
 
1762
  registry.remove(engine);
 
1763
  delete engine;
 
1764
 
 
1765
  pthread_mutex_destroy(&THR_LOCK_myisam);
 
1766
 
 
1767
  return mi_panic(HA_PANIC_CLOSE);
 
1768
}
 
1769
 
 
1770
 
 
1771
/****************************************************************************
 
1772
 * MyISAM MRR implementation: use DS-MRR
 
1773
 ***************************************************************************/
 
1774
 
 
1775
int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
 
1776
                                     uint32_t n_ranges, uint32_t mode,
 
1777
                                     HANDLER_BUFFER *buf)
 
1778
{
 
1779
  return ds_mrr.dsmrr_init(this, &table->key_info[active_index],
 
1780
                           seq, seq_init_param, n_ranges, mode, buf);
 
1781
}
 
1782
 
 
1783
int ha_myisam::multi_range_read_next(char **range_info)
 
1784
{
 
1785
  return ds_mrr.dsmrr_next(this, range_info);
 
1786
}
 
1787
 
 
1788
ha_rows ha_myisam::multi_range_read_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
 
1789
                                               void *seq_init_param,
 
1790
                                               uint32_t n_ranges, uint32_t *bufsz,
 
1791
                                               uint32_t *flags, COST_VECT *cost)
 
1792
{
 
1793
  /*
 
1794
    This call is here because there is no location where this->table would
 
1795
    already be known.
 
1796
    TODO: consider moving it into some per-query initialization call.
 
1797
  */
 
1798
  ds_mrr.init(this, table);
 
1799
  return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz,
 
1800
                                 flags, cost);
 
1801
}
 
1802
 
 
1803
int ha_myisam::multi_range_read_info(uint32_t keyno, uint32_t n_ranges, uint32_t keys,
 
1804
                                     uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
 
1805
{
 
1806
  ds_mrr.init(this, table);
 
1807
  return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
 
1808
}
 
1809
 
 
1810
/* MyISAM MRR implementation ends */
 
1811
 
 
1812
 
 
1813
/* Index condition pushdown implementation*/
 
1814
 
 
1815
 
 
1816
Item *ha_myisam::idx_cond_push(uint32_t keyno_arg, Item* idx_cond_arg)
 
1817
{
 
1818
  pushed_idx_cond_keyno= keyno_arg;
 
1819
  pushed_idx_cond= idx_cond_arg;
 
1820
  in_range_check_pushed_down= true;
 
1821
  if (active_index == pushed_idx_cond_keyno)
 
1822
    mi_set_index_cond_func(file, index_cond_func_myisam, this);
 
1823
  return NULL;
 
1824
}
 
1825
 
 
1826
static DRIZZLE_SYSVAR_UINT(block_size, block_size,
 
1827
                           PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
1828
                           N_("Block size to be used for MyISAM index pages."),
 
1829
                           NULL, NULL, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH, 
 
1830
                           MI_MAX_KEY_BLOCK_LENGTH, 0);
1669
1831
 
1670
1832
static DRIZZLE_SYSVAR_UINT(repair_threads, repair_threads,
1671
 
                            PLUGIN_VAR_RQCMDARG,
1672
 
                            N_("Number of threads to use when repairing MyISAM tables. The value of "
1673
 
                            "1 disables parallel repair."),
1674
 
                            NULL, NULL, 1, 1, UINT32_MAX, 0);
 
1833
                           PLUGIN_VAR_RQCMDARG,
 
1834
                           N_("Number of threads to use when repairing MyISAM tables. The value of "
 
1835
                              "1 disables parallel repair."),
 
1836
                           NULL, NULL, 1, 1, UINT32_MAX, 0);
1675
1837
 
1676
1838
static DRIZZLE_SYSVAR_ULONGLONG(max_sort_file_size, max_sort_file_size,
1677
1839
                                PLUGIN_VAR_RQCMDARG,
1685
1847
 
1686
1848
extern uint32_t data_pointer_size;
1687
1849
static DRIZZLE_SYSVAR_UINT(data_pointer_size, data_pointer_size,
1688
 
                            PLUGIN_VAR_RQCMDARG,
1689
 
                            N_("Default pointer size to be used for MyISAM tables."),
1690
 
                            NULL, NULL, 6, 2, 7, 0);
 
1850
                           PLUGIN_VAR_RQCMDARG,
 
1851
                           N_("Default pointer size to be used for MyISAM tables."),
 
1852
                           NULL, NULL, 6, 2, 7, 0);
1691
1853
 
1692
 
static drizzle_sys_var* sys_variables[]= {
1693
 
  DRIZZLE_SYSVAR(key_cache_block_size),
1694
 
  DRIZZLE_SYSVAR(key_cache_size),
1695
 
  DRIZZLE_SYSVAR(key_cache_division_limit),
1696
 
  DRIZZLE_SYSVAR(key_cache_age_threshold),
 
1854
static struct st_mysql_sys_var* system_variables[]= {
 
1855
  DRIZZLE_SYSVAR(block_size),
1697
1856
  DRIZZLE_SYSVAR(repair_threads),
1698
1857
  DRIZZLE_SYSVAR(max_sort_file_size),
1699
1858
  DRIZZLE_SYSVAR(sort_buffer_size),
1702
1861
};
1703
1862
 
1704
1863
 
1705
 
DRIZZLE_DECLARE_PLUGIN
 
1864
drizzle_declare_plugin(myisam)
1706
1865
{
1707
 
  DRIZZLE_VERSION_ID,
1708
1866
  "MyISAM",
1709
1867
  "1.0",
1710
1868
  "MySQL AB",
1711
1869
  "Default engine as of MySQL 3.23 with great performance",
1712
1870
  PLUGIN_LICENSE_GPL,
1713
1871
  myisam_init, /* Plugin Init */
1714
 
  sys_variables,           /* system variables */
 
1872
  myisam_deinit, /* Plugin Deinit */
 
1873
  NULL,                       /* status variables                */
 
1874
  system_variables,           /* system variables */
1715
1875
  NULL                        /* config options                  */
1716
1876
}
1717
 
DRIZZLE_DECLARE_PLUGIN_END;
 
1877
drizzle_declare_plugin_end;