~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/ha_myisam.cc

  • Committer: Monty Taylor
  • Date: 2009-03-08 23:45:12 UTC
  • mto: (923.2.1 mordred)
  • mto: This revision was merged to the branch mainline in revision 921.
  • Revision ID: mordred@inaugust.com-20090308234512-tqkygxtu1iaig23s
Removed C99 isnan() usage, which allows us to remove the util/math.{cc,h} workarounds. Yay for standards!

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
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 */
15
 
 
16
 
 
17
 
 
18
 
#include <config.h>
19
 
#include <drizzled/internal/my_bit.h>
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
 
 
17
 
 
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>
 
22
#include "myisamdef.h"
26
23
#include <drizzled/util/test.h>
27
24
#include <drizzled/error.h>
28
25
#include <drizzled/errmsg_print.h>
29
26
#include <drizzled/gettext.h>
30
27
#include <drizzled/session.h>
31
 
#include <drizzled/plugin.h>
32
 
#include <drizzled/plugin/client.h>
 
28
#include <drizzled/protocol.h>
33
29
#include <drizzled/table.h>
34
 
#include <drizzled/memory/multi_malloc.h>
35
 
#include <drizzled/plugin/daemon.h>
36
 
 
37
 
#include <drizzled/plugin/storage_engine.h>
38
 
 
39
 
#include <boost/algorithm/string.hpp>
40
 
#include <boost/scoped_ptr.hpp>
41
 
 
42
 
#include <string>
43
 
#include <sstream>
44
 
#include <map>
45
 
#include <algorithm>
46
 
#include <memory>
47
 
#include <boost/program_options.hpp>
48
 
#include <drizzled/module/option_map.h>
49
 
 
50
 
namespace po= boost::program_options;
51
 
 
52
 
using namespace std;
53
 
using namespace drizzled;
54
 
 
55
 
static const string engine_name("MyISAM");
56
 
 
57
 
boost::mutex THR_LOCK_myisam;
58
 
 
59
 
static uint32_t myisam_key_cache_block_size= KEY_CACHE_BLOCK_SIZE;
60
 
static uint32_t myisam_key_cache_size;
61
 
static uint32_t myisam_key_cache_division_limit;
62
 
static uint32_t myisam_key_cache_age_threshold;
 
30
#include <drizzled/field/timestamp.h>
 
31
 
 
32
ulong myisam_recover_options= HA_RECOVER_NONE;
 
33
pthread_mutex_t THR_LOCK_myisam= PTHREAD_MUTEX_INITIALIZER;
 
34
 
 
35
static uint32_t repair_threads;
 
36
static uint32_t block_size;
63
37
static uint64_t max_sort_file_size;
64
 
typedef constrained_check<size_t, SIZE_MAX, 1024, 1024> sort_buffer_constraint;
65
 
static sort_buffer_constraint sort_buffer_size;
66
 
 
67
 
void st_mi_isam_share::setKeyCache()
68
 
{
69
 
  (void)init_key_cache(&key_cache,
70
 
                       myisam_key_cache_block_size,
71
 
                       myisam_key_cache_size,
72
 
                       myisam_key_cache_division_limit, 
73
 
                       myisam_key_cache_age_threshold);
74
 
}
 
38
static uint64_t sort_buffer_size;
 
39
 
 
40
/* bits in myisam_recover_options */
 
41
const char *myisam_recover_names[] =
 
42
{ "DEFAULT", "BACKUP", "FORCE", "QUICK", NULL};
 
43
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
 
44
                                 myisam_recover_names, NULL};
 
45
 
 
46
const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal",
 
47
                                           "nulls_ignored", NULL};
 
48
TYPELIB myisam_stats_method_typelib= {
 
49
  array_elements(myisam_stats_method_names) - 1, "",
 
50
  myisam_stats_method_names, NULL};
 
51
 
75
52
 
76
53
/*****************************************************************************
77
54
** MyISAM tables
78
55
*****************************************************************************/
79
56
 
80
 
static const char *ha_myisam_exts[] = {
81
 
  ".MYI",
82
 
  ".MYD",
83
 
  NULL
84
 
};
85
 
 
86
 
class MyisamEngine : public plugin::StorageEngine
87
 
{
88
 
  MyisamEngine();
89
 
  MyisamEngine(const MyisamEngine&);
90
 
  MyisamEngine& operator=(const MyisamEngine&);
91
 
public:
92
 
  explicit MyisamEngine(string name_arg) :
93
 
    plugin::StorageEngine(name_arg,
94
 
                          HTON_CAN_INDEX_BLOBS |
95
 
                          HTON_STATS_RECORDS_IS_EXACT |
96
 
                          HTON_TEMPORARY_ONLY |
97
 
                          HTON_NULL_IN_KEY |
98
 
                          HTON_HAS_RECORDS |
99
 
                          HTON_DUPLICATE_POS |
100
 
                          HTON_AUTO_PART_KEY |
101
 
                          HTON_SKIP_STORE_LOCK)
102
 
  {
103
 
  }
104
 
 
105
 
  virtual ~MyisamEngine()
106
 
  { 
107
 
    mi_panic(HA_PANIC_CLOSE);
108
 
  }
109
 
 
110
 
  virtual Cursor *create(Table &table)
111
 
  {
112
 
    return new ha_myisam(*this, table);
113
 
  }
114
 
 
115
 
  const char **bas_ext() const {
116
 
    return ha_myisam_exts;
117
 
  }
118
 
 
119
 
  int doCreateTable(Session&,
120
 
                    Table& table_arg,
121
 
                    const identifier::Table &identifier,
122
 
                    message::Table&);
123
 
 
124
 
  int doRenameTable(Session&, const identifier::Table &from, const identifier::Table &to);
125
 
 
126
 
  int doDropTable(Session&, const identifier::Table &identifier);
127
 
 
128
 
  int doGetTableDefinition(Session& session,
129
 
                           const identifier::Table &identifier,
130
 
                           message::Table &table_message);
131
 
 
132
 
  uint32_t max_supported_keys()          const { return MI_MAX_KEY; }
133
 
  uint32_t max_supported_key_length()    const { return MI_MAX_KEY_LENGTH; }
134
 
  uint32_t max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
135
 
 
136
 
  uint32_t index_flags(enum  ha_key_alg) const
137
 
  {
138
 
    return (HA_READ_NEXT |
139
 
            HA_READ_PREV |
140
 
            HA_READ_RANGE |
141
 
            HA_READ_ORDER |
142
 
            HA_KEYREAD_ONLY);
143
 
  }
144
 
  bool doDoesTableExist(Session& session, const identifier::Table &identifier);
145
 
 
146
 
  void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
147
 
                             const drizzled::identifier::Schema &schema_identifier,
148
 
                             drizzled::identifier::Table::vector &set_of_identifiers);
149
 
  bool validateCreateTableOption(const std::string &key, const std::string &state)
150
 
  {
151
 
    (void)state;
152
 
    if (boost::iequals(key, "ROW_FORMAT"))
153
 
    {
154
 
      return true;
155
 
    }
156
 
 
157
 
    return false;
158
 
  }
159
 
};
160
 
 
161
 
void MyisamEngine::doGetTableIdentifiers(drizzled::CachedDirectory&,
162
 
                                         const drizzled::identifier::Schema&,
163
 
                                         drizzled::identifier::Table::vector&)
164
 
{
165
 
}
166
 
 
167
 
bool MyisamEngine::doDoesTableExist(Session &session, const identifier::Table &identifier)
168
 
{
169
 
  return session.getMessageCache().doesTableMessageExist(identifier);
170
 
}
171
 
 
172
 
int MyisamEngine::doGetTableDefinition(Session &session,
173
 
                                       const identifier::Table &identifier,
174
 
                                       message::Table &table_message)
175
 
{
176
 
  if (session.getMessageCache().getTableMessage(identifier, table_message))
177
 
    return EEXIST;
178
 
  return ENOENT;
179
 
}
180
 
 
181
 
/* 
182
 
  Convert to push_Warnings if you ever care about this, otherwise, it is a no-op.
183
 
*/
184
 
 
185
 
static void mi_check_print_msg(MI_CHECK *,      const char* ,
186
 
                               const char *, va_list )
187
 
{
 
57
static handler *myisam_create_handler(handlerton *hton,
 
58
                                      TABLE_SHARE *table,
 
59
                                      MEM_ROOT *mem_root)
 
60
{
 
61
  return new (mem_root) ha_myisam(hton, table);
 
62
}
 
63
 
 
64
// collect errors printed by mi_check routines
 
65
 
 
66
static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
 
67
                               const char *fmt, va_list args)
 
68
{
 
69
  Session* session = (Session*)param->session;
 
70
  Protocol *protocol= session->protocol;
 
71
  uint32_t length, msg_length;
 
72
  char msgbuf[MI_MAX_MSG_BUF];
 
73
  char name[NAME_LEN*2+2];
 
74
 
 
75
  msg_length= vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
 
76
  msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
 
77
 
 
78
  if (!session->drizzleclient_vio_ok())
 
79
  {
 
80
    errmsg_printf(ERRMSG_LVL_ERROR, "%s",msgbuf);
 
81
    return;
 
82
  }
 
83
 
 
84
  if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
 
85
                         T_AUTO_REPAIR))
 
86
  {
 
87
    my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
 
88
    return;
 
89
  }
 
90
  length= sprintf(name,"%s.%s",param->db_name,param->table_name);
 
91
 
 
92
  /*
 
93
    TODO: switch from protocol to push_warning here. The main reason we didn't
 
94
    it yet is parallel repair. Due to following trace:
 
95
    mi_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr.
 
96
 
 
97
    Also we likely need to lock mutex here (in both cases with protocol and
 
98
    push_warning).
 
99
  */
 
100
  protocol->prepare_for_resend();
 
101
  protocol->store(name, length, system_charset_info);
 
102
  protocol->store(param->op_name, system_charset_info);
 
103
  protocol->store(msg_type, system_charset_info);
 
104
  protocol->store(msgbuf, msg_length, system_charset_info);
 
105
  if (protocol->write())
 
106
    errmsg_printf(ERRMSG_LVL_ERROR, "Failed on drizzleclient_net_write, writing to stderr instead: %s\n",
 
107
                    msgbuf);
 
108
  return;
188
109
}
189
110
 
190
111
 
204
125
    table conformance in merge engine.
205
126
 
206
127
    The caller needs to free *recinfo_out after use. Since *recinfo_out
207
 
    and *keydef_out are allocated with a multi_malloc, *keydef_out
 
128
    and *keydef_out are allocated with a my_multi_malloc, *keydef_out
208
129
    is freed automatically when *recinfo_out is freed.
209
130
 
210
131
  RETURN VALUE
212
133
    !0 error code
213
134
*/
214
135
 
215
 
static int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
216
 
                        MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
 
136
int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
 
137
                 MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
217
138
{
218
139
  uint32_t i, j, recpos, minpos, fieldpos, temp_length, length;
219
140
  enum ha_base_keytype type= HA_KEYTYPE_BINARY;
220
141
  unsigned char *record;
 
142
  KEY *pos;
221
143
  MI_KEYDEF *keydef;
222
144
  MI_COLUMNDEF *recinfo, *recinfo_pos;
223
145
  HA_KEYSEG *keyseg;
224
 
  TableShare *share= table_arg->getMutableShare();
 
146
  TABLE_SHARE *share= table_arg->s;
225
147
  uint32_t options= share->db_options_in_use;
226
 
  if (!(memory::multi_malloc(false,
227
 
          recinfo_out, (share->sizeFields() * 2 + 2) * sizeof(MI_COLUMNDEF),
228
 
          keydef_out, share->sizeKeys() * sizeof(MI_KEYDEF),
229
 
          &keyseg, (share->key_parts + share->sizeKeys()) * sizeof(HA_KEYSEG),
 
148
  if (!(my_multi_malloc(MYF(MY_WME),
 
149
          recinfo_out, (share->fields * 2 + 2) * sizeof(MI_COLUMNDEF),
 
150
          keydef_out, share->keys * sizeof(MI_KEYDEF),
 
151
          &keyseg,
 
152
          (share->key_parts + share->keys) * sizeof(HA_KEYSEG),
230
153
          NULL)))
231
 
    return(HA_ERR_OUT_OF_MEM);
 
154
    return(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
232
155
  keydef= *keydef_out;
233
156
  recinfo= *recinfo_out;
234
 
  for (i= 0; i < share->sizeKeys(); i++)
 
157
  pos= table_arg->key_info;
 
158
  for (i= 0; i < share->keys; i++, pos++)
235
159
  {
236
 
    KeyInfo *pos= &table_arg->key_info[i];
237
160
    keydef[i].flag= ((uint16_t) pos->flags & (HA_NOSAME));
238
161
    keydef[i].key_alg= HA_KEY_ALG_BTREE;
239
162
    keydef[i].block_length= pos->block_size;
251
174
      {
252
175
        if (pos->key_part[j].length > 8 &&
253
176
            (type == HA_KEYTYPE_TEXT ||
 
177
             type == HA_KEYTYPE_NUM ||
254
178
             (type == HA_KEYTYPE_BINARY && !field->zero_pack())))
255
179
        {
256
180
          /* No blobs here */
274
198
      {
275
199
        keydef[i].seg[j].null_bit= field->null_bit;
276
200
        keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
277
 
                                           (unsigned char*) table_arg->getInsertRecord());
 
201
                                           (unsigned char*) table_arg->record[0]);
278
202
      }
279
203
      else
280
204
      {
286
210
        keydef[i].seg[j].flag|= HA_BLOB_PART;
287
211
        /* save number of bytes used to pack length */
288
212
        keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
289
 
                                            share->sizeBlobPtr());
 
213
                                            share->blob_ptr_size);
290
214
      }
291
215
    }
292
216
    keyseg+= pos->key_parts;
293
217
  }
294
218
  if (table_arg->found_next_number_field)
295
219
    keydef[share->next_number_index].flag|= HA_AUTO_KEY;
296
 
  record= table_arg->getInsertRecord();
 
220
  record= table_arg->record[0];
297
221
  recpos= 0;
298
222
  recinfo_pos= recinfo;
299
 
 
300
 
  while (recpos < (uint) share->sizeStoredRecord())
 
223
  while (recpos < (uint) share->stored_rec_length)
301
224
  {
302
225
    Field **field, *found= 0;
303
 
    minpos= share->getRecordLength();
 
226
    minpos= share->reclength;
304
227
    length= 0;
305
228
 
306
 
    for (field= table_arg->getFields(); *field; field++)
 
229
    for (field= table_arg->field; *field; field++)
307
230
    {
308
231
      if ((fieldpos= (*field)->offset(record)) >= recpos &&
309
232
          fieldpos <= minpos)
311
234
        /* skip null fields */
312
235
        if (!(temp_length= (*field)->pack_length_in_rec()))
313
236
          continue; /* Skip null-fields */
314
 
 
315
237
        if (! found || fieldpos < minpos ||
316
238
            (fieldpos == minpos && temp_length < length))
317
239
        {
344
266
    {
345
267
      recinfo_pos->null_bit= found->null_bit;
346
268
      recinfo_pos->null_pos= (uint) (found->null_ptr -
347
 
                                     (unsigned char*) table_arg->getInsertRecord());
 
269
                                     (unsigned char*) table_arg->record[0]);
348
270
    }
349
271
    else
350
272
    {
358
280
  return(0);
359
281
}
360
282
 
361
 
int ha_myisam::reset_auto_increment(uint64_t value)
362
 
{
363
 
  file->s->state.auto_increment= value;
364
 
  return 0;
365
 
}
366
283
 
367
284
/*
368
285
  Check for underlying table conformance
404
321
      (should be corretly detected in table2myisam).
405
322
*/
406
323
 
407
 
static int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
408
 
                            uint32_t t1_keys, uint32_t t1_recs,
409
 
                            MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
410
 
                            uint32_t t2_keys, uint32_t t2_recs, bool strict)
 
324
int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
 
325
                     uint32_t t1_keys, uint32_t t1_recs,
 
326
                     MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
 
327
                     uint32_t t2_keys, uint32_t t2_recs, bool strict)
411
328
{
412
329
  uint32_t i, j;
413
330
  if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys))
442
359
      {
443
360
        if ((t1_keysegs_j__type == HA_KEYTYPE_VARTEXT2) &&
444
361
            (t2_keysegs[j].type == HA_KEYTYPE_VARTEXT1))
445
 
          t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1;
 
362
          t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1; /* purecov: tested */
446
363
        else if ((t1_keysegs_j__type == HA_KEYTYPE_VARBINARY2) &&
447
364
                 (t2_keysegs[j].type == HA_KEYTYPE_VARBINARY1))
448
 
          t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1;
 
365
          t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1; /* purecov: inspected */
449
366
      }
450
367
 
451
368
      if (t1_keysegs_j__type != t2_keysegs[j].type ||
479
396
}
480
397
 
481
398
 
 
399
extern "C" {
 
400
 
482
401
volatile int *killed_ptr(MI_CHECK *param)
483
402
{
484
403
  /* In theory Unsafe conversion, but should be ok for now */
485
 
  return (int*) (((Session *)(param->session))->getKilledPtr());
 
404
  return (int*) &(((Session *)(param->session))->killed);
486
405
}
487
406
 
488
407
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
532
451
                        const char *sfile, uint32_t sline)
533
452
{
534
453
  Session *cur_session;
535
 
  if ((cur_session= file->in_use))
536
 
  {
537
 
    errmsg_printf(error::ERROR, _("Got an error from thread_id=%"PRIu64", %s:%d"),
 
454
  LIST *element;
 
455
  pthread_mutex_lock(&file->s->intern_lock);
 
456
  if ((cur_session= (Session*) file->in_use.data))
 
457
    errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from thread_id=%"PRIu64", %s:%d"),
538
458
                    cur_session->thread_id,
539
459
                    sfile, sline);
540
 
  }
541
460
  else
542
 
  {
543
 
    errmsg_printf(error::ERROR, _("Got an error from unknown thread, %s:%d"), sfile, sline);
544
 
  }
545
 
 
 
461
    errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from unknown thread, %s:%d"), sfile, sline);
546
462
  if (message)
547
 
    errmsg_printf(error::ERROR, "%s", message);
548
 
 
549
 
  list<Session *>::iterator it= file->s->in_use->begin();
550
 
  while (it != file->s->in_use->end())
 
463
    errmsg_printf(ERRMSG_LVL_ERROR, "%s", message);
 
464
  for (element= file->s->in_use; element; element= list_rest(element))
551
465
  {
552
 
    errmsg_printf(error::ERROR, "%s", _("Unknown thread accessing table"));
553
 
    ++it;
 
466
    errmsg_printf(ERRMSG_LVL_ERROR, "%s", _("Unknown thread accessing table"));
554
467
  }
555
 
}
556
 
 
557
 
ha_myisam::ha_myisam(plugin::StorageEngine &engine_arg,
558
 
                     Table &table_arg)
559
 
  : Cursor(engine_arg, table_arg),
560
 
  file(0),
561
 
  can_enable_indexes(true),
562
 
  is_ordered(true)
563
 
{ }
564
 
 
565
 
Cursor *ha_myisam::clone(memory::Root *mem_root)
 
468
  pthread_mutex_unlock(&file->s->intern_lock);
 
469
}
 
470
 
 
471
}
 
472
 
 
473
ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
 
474
  :handler(hton, table_arg), file(0),
 
475
  int_table_flags(HA_NULL_IN_KEY |
 
476
                  HA_BINLOG_ROW_CAPABLE |
 
477
                  HA_BINLOG_STMT_CAPABLE |
 
478
                  HA_DUPLICATE_POS |
 
479
                  HA_CAN_INDEX_BLOBS |
 
480
                  HA_AUTO_PART_KEY |
 
481
                  HA_FILE_BASED |
 
482
                  HA_NO_TRANSACTIONS |
 
483
                  HA_HAS_RECORDS |
 
484
                  HA_STATS_RECORDS_IS_EXACT |
 
485
                  HA_NEED_READ_RANGE_BUFFER |
 
486
                  HA_MRR_CANT_SORT),
 
487
   can_enable_indexes(1)
 
488
{}
 
489
 
 
490
handler *ha_myisam::clone(MEM_ROOT *mem_root)
566
491
{
567
 
  ha_myisam *new_handler= static_cast <ha_myisam *>(Cursor::clone(mem_root));
 
492
  ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(mem_root));
568
493
  if (new_handler)
569
494
    new_handler->file->state= file->state;
570
495
  return new_handler;
571
496
}
572
497
 
 
498
 
 
499
static const char *ha_myisam_exts[] = {
 
500
  ".MYI",
 
501
  ".MYD",
 
502
  NULL
 
503
};
 
504
 
 
505
const char **ha_myisam::bas_ext() const
 
506
{
 
507
  return ha_myisam_exts;
 
508
}
 
509
 
 
510
 
573
511
const char *ha_myisam::index_type(uint32_t )
574
512
{
575
513
  return "BTREE";
576
514
}
577
515
 
578
516
/* Name is here without an extension */
579
 
int ha_myisam::doOpen(const drizzled::identifier::Table &identifier, int mode, uint32_t test_if_locked)
 
517
int ha_myisam::open(const char *name, int mode, uint32_t test_if_locked)
580
518
{
581
519
  MI_KEYDEF *keyinfo;
582
520
  MI_COLUMNDEF *recinfo= 0;
598
536
    open of a table that is in use by other threads already (if the
599
537
    MyISAM share exists already).
600
538
  */
601
 
  if (!(file= mi_open(identifier, mode, test_if_locked)))
602
 
    return (errno ? errno : -1);
603
 
 
604
 
  if (!getTable()->getShare()->getType()) /* No need to perform a check for tmp table */
 
539
  if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
 
540
    return (my_errno ? my_errno : -1);
 
541
  if (!table->s->tmp_table) /* No need to perform a check for tmp table */
605
542
  {
606
 
    if ((errno= table2myisam(getTable(), &keyinfo, &recinfo, &recs)))
 
543
    if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs)))
607
544
    {
 
545
      /* purecov: begin inspected */
608
546
      goto err;
 
547
      /* purecov: end */
609
548
    }
610
 
    if (check_definition(keyinfo, recinfo, getTable()->getShare()->sizeKeys(), recs,
 
549
    if (check_definition(keyinfo, recinfo, table->s->keys, recs,
611
550
                         file->s->keyinfo, file->s->rec,
612
551
                         file->s->base.keys, file->s->base.fields, true))
613
552
    {
614
 
      errno= HA_ERR_CRASHED;
 
553
      /* purecov: begin inspected */
 
554
      my_errno= HA_ERR_CRASHED;
615
555
      goto err;
 
556
      /* purecov: end */
616
557
    }
617
558
  }
618
559
 
619
 
  assert(test_if_locked);
620
560
  if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
621
561
    mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0);
622
562
 
623
563
  info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
624
564
  if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
625
565
    mi_extra(file, HA_EXTRA_WAIT_LOCK, 0);
626
 
  if (!getTable()->getShare()->db_record_offset)
627
 
    is_ordered= false;
628
 
 
629
 
 
630
 
  keys_with_parts.reset();
631
 
  for (i= 0; i < getTable()->getShare()->sizeKeys(); i++)
 
566
  if (!table->s->db_record_offset)
 
567
    int_table_flags|=HA_REC_NOT_IN_SEQ;
 
568
  if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
 
569
    int_table_flags|=HA_HAS_CHECKSUM;
 
570
 
 
571
  keys_with_parts.clear_all();
 
572
  for (i= 0; i < table->s->keys; i++)
632
573
  {
633
 
    getTable()->key_info[i].block_size= file->s->keyinfo[i].block_length;
 
574
    table->key_info[i].block_size= file->s->keyinfo[i].block_length;
634
575
 
635
 
    KeyPartInfo *kp= getTable()->key_info[i].key_part;
636
 
    KeyPartInfo *kp_end= kp + getTable()->key_info[i].key_parts;
 
576
    KEY_PART_INFO *kp= table->key_info[i].key_part;
 
577
    KEY_PART_INFO *kp_end= kp + table->key_info[i].key_parts;
637
578
    for (; kp != kp_end; kp++)
638
579
    {
639
 
      if (!kp->field->part_of_key.test(i))
 
580
      if (!kp->field->part_of_key.is_set(i))
640
581
      {
641
 
        keys_with_parts.set(i);
 
582
        keys_with_parts.set_bit(i);
642
583
        break;
643
584
      }
644
585
    }
645
586
  }
646
 
  errno= 0;
 
587
  my_errno= 0;
647
588
  goto end;
648
589
 err:
649
590
  this->close();
650
591
 end:
651
592
  /*
652
 
    Both recinfo and keydef are allocated by multi_malloc(), thus only
 
593
    Both recinfo and keydef are allocated by my_multi_malloc(), thus only
653
594
    recinfo must be freed.
654
595
  */
655
596
  if (recinfo)
656
597
    free((unsigned char*) recinfo);
657
 
  return errno;
 
598
  return my_errno;
658
599
}
659
600
 
660
601
int ha_myisam::close(void)
664
605
  return mi_close(tmp);
665
606
}
666
607
 
667
 
int ha_myisam::doInsertRecord(unsigned char *buf)
 
608
int ha_myisam::write_row(unsigned char *buf)
668
609
{
 
610
  ha_statistic_increment(&SSV::ha_write_count);
 
611
 
669
612
  /*
670
613
    If we have an auto_increment column and we are writing a changed row
671
614
    or a new row, then update the auto_increment value in the record.
672
615
  */
673
 
  if (getTable()->next_number_field && buf == getTable()->getInsertRecord())
 
616
  if (table->next_number_field && buf == table->record[0])
674
617
  {
675
618
    int error;
676
619
    if ((error= update_auto_increment()))
679
622
  return mi_write(file,buf);
680
623
}
681
624
 
 
625
int ha_myisam::check(Session* session, HA_CHECK_OPT* check_opt)
 
626
{
 
627
  if (!file) return HA_ADMIN_INTERNAL_ERROR;
 
628
  int error;
 
629
  MI_CHECK param;
 
630
  MYISAM_SHARE* share = file->s;
 
631
  const char *old_proc_info= session->get_proc_info();
 
632
 
 
633
  session->set_proc_info("Checking table");
 
634
  myisamchk_init(&param);
 
635
  param.session = session;
 
636
  param.op_name =   "check";
 
637
  param.db_name=    table->s->db.str;
 
638
  param.table_name= table->alias;
 
639
  param.testflag = check_opt->flags | T_CHECK | T_SILENT;
 
640
  param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
 
641
 
 
642
  if (!(table->db_stat & HA_READ_ONLY))
 
643
    param.testflag|= T_STATISTICS;
 
644
  param.using_global_keycache = 1;
 
645
 
 
646
  if (!mi_is_crashed(file) &&
 
647
      (((param.testflag & T_CHECK_ONLY_CHANGED) &&
 
648
        !(share->state.changed & (STATE_CHANGED | STATE_CRASHED |
 
649
                                  STATE_CRASHED_ON_REPAIR)) &&
 
650
        share->state.open_count == 0) ||
 
651
       ((param.testflag & T_FAST) && (share->state.open_count ==
 
652
                                      (uint) (share->global_changed ? 1 : 0)))))
 
653
    return HA_ADMIN_ALREADY_DONE;
 
654
 
 
655
  error = chk_status(&param, file);             // Not fatal
 
656
  error = chk_size(&param, file);
 
657
  if (!error)
 
658
    error |= chk_del(&param, file, param.testflag);
 
659
  if (!error)
 
660
    error = chk_key(&param, file);
 
661
  if (!error)
 
662
  {
 
663
    if ((!(param.testflag & T_QUICK) &&
 
664
         ((share->options &
 
665
           (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
 
666
          (param.testflag & (T_EXTEND | T_MEDIUM)))) ||
 
667
        mi_is_crashed(file))
 
668
    {
 
669
      uint32_t old_testflag=param.testflag;
 
670
      param.testflag|=T_MEDIUM;
 
671
      if (!(error= init_io_cache(&param.read_cache, file->dfile,
 
672
                                 my_default_record_cache_size, READ_CACHE,
 
673
                                 share->pack.header_length, 1, MYF(MY_WME))))
 
674
      {
 
675
        error= chk_data_link(&param, file, param.testflag & T_EXTEND);
 
676
        end_io_cache(&(param.read_cache));
 
677
      }
 
678
      param.testflag= old_testflag;
 
679
    }
 
680
  }
 
681
  if (!error)
 
682
  {
 
683
    if ((share->state.changed & (STATE_CHANGED |
 
684
                                 STATE_CRASHED_ON_REPAIR |
 
685
                                 STATE_CRASHED | STATE_NOT_ANALYZED)) ||
 
686
        (param.testflag & T_STATISTICS) ||
 
687
        mi_is_crashed(file))
 
688
    {
 
689
      file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
 
690
      pthread_mutex_lock(&share->intern_lock);
 
691
      share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
 
692
                               STATE_CRASHED_ON_REPAIR);
 
693
      if (!(table->db_stat & HA_READ_ONLY))
 
694
        error=update_state_info(&param,file,UPDATE_TIME | UPDATE_OPEN_COUNT |
 
695
                                UPDATE_STAT);
 
696
      pthread_mutex_unlock(&share->intern_lock);
 
697
      info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
 
698
           HA_STATUS_CONST);
 
699
    }
 
700
  }
 
701
  else if (!mi_is_crashed(file) && !session->killed)
 
702
  {
 
703
    mi_mark_crashed(file);
 
704
    file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
 
705
  }
 
706
 
 
707
  session->set_proc_info(old_proc_info);
 
708
  return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
 
709
}
 
710
 
 
711
 
 
712
/*
 
713
  analyze the key distribution in the table
 
714
  As the table may be only locked for read, we have to take into account that
 
715
  two threads may do an analyze at the same time!
 
716
*/
 
717
 
 
718
int ha_myisam::analyze(Session *session,
 
719
                       HA_CHECK_OPT* )
 
720
{
 
721
  int error=0;
 
722
  MI_CHECK param;
 
723
  MYISAM_SHARE* share = file->s;
 
724
 
 
725
  myisamchk_init(&param);
 
726
  param.session = session;
 
727
  param.op_name=    "analyze";
 
728
  param.db_name=    table->s->db.str;
 
729
  param.table_name= table->alias;
 
730
  param.testflag= (T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
 
731
                   T_DONT_CHECK_CHECKSUM);
 
732
  param.using_global_keycache = 1;
 
733
  param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
 
734
 
 
735
  if (!(share->state.changed & STATE_NOT_ANALYZED))
 
736
    return HA_ADMIN_ALREADY_DONE;
 
737
 
 
738
  error = chk_key(&param, file);
 
739
  if (!error)
 
740
  {
 
741
    pthread_mutex_lock(&share->intern_lock);
 
742
    error=update_state_info(&param,file,UPDATE_STAT);
 
743
    pthread_mutex_unlock(&share->intern_lock);
 
744
  }
 
745
  else if (!mi_is_crashed(file) && !session->killed)
 
746
    mi_mark_crashed(file);
 
747
  return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
 
748
}
 
749
 
 
750
 
 
751
int ha_myisam::repair(Session* session, HA_CHECK_OPT *check_opt)
 
752
{
 
753
  int error;
 
754
  MI_CHECK param;
 
755
  ha_rows start_records;
 
756
 
 
757
  if (!file) return HA_ADMIN_INTERNAL_ERROR;
 
758
 
 
759
  myisamchk_init(&param);
 
760
  param.session = session;
 
761
  param.op_name=  "repair";
 
762
  param.testflag= ((check_opt->flags & ~(T_EXTEND)) |
 
763
                   T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM |
 
764
                   (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
 
765
  param.sort_buffer_length=  (size_t)sort_buffer_size;
 
766
 
 
767
  // Release latches since this can take a long time
 
768
  ha_release_temporary_latches(session);
 
769
 
 
770
  start_records=file->state->records;
 
771
  while ((error=repair(session,param,0)) && param.retry_repair)
 
772
  {
 
773
    param.retry_repair=0;
 
774
    if (test_all_bits(param.testflag,
 
775
                      (uint) (T_RETRY_WITHOUT_QUICK | T_QUICK)))
 
776
    {
 
777
      param.testflag&= ~T_RETRY_WITHOUT_QUICK;
 
778
      errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' without quick",
 
779
                            table->s->path.str);
 
780
      continue;
 
781
    }
 
782
    param.testflag&= ~T_QUICK;
 
783
    if ((param.testflag & T_REP_BY_SORT))
 
784
    {
 
785
      param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
 
786
      errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' with keycache",
 
787
                            table->s->path.str);
 
788
      continue;
 
789
    }
 
790
    break;
 
791
  }
 
792
  if (!error && start_records != file->state->records &&
 
793
      !(check_opt->flags & T_VERY_SILENT))
 
794
  {
 
795
    char llbuff[22],llbuff2[22];
 
796
    errmsg_printf(ERRMSG_LVL_INFO, "Found %s of %s rows when repairing '%s'",
 
797
                          llstr(file->state->records, llbuff),
 
798
                          llstr(start_records, llbuff2),
 
799
                          table->s->path.str);
 
800
  }
 
801
  return error;
 
802
}
 
803
 
 
804
int ha_myisam::optimize(Session* session, HA_CHECK_OPT *check_opt)
 
805
{
 
806
  int error;
 
807
  if (!file) return HA_ADMIN_INTERNAL_ERROR;
 
808
  MI_CHECK param;
 
809
 
 
810
  myisamchk_init(&param);
 
811
  param.session = session;
 
812
  param.op_name= "optimize";
 
813
  param.testflag= (check_opt->flags | T_SILENT | T_FORCE_CREATE |
 
814
                   T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
 
815
  param.sort_buffer_length= (size_t)sort_buffer_size;
 
816
  if ((error= repair(session,param,1)) && param.retry_repair)
 
817
  {
 
818
    errmsg_printf(ERRMSG_LVL_WARN, "Warning: Optimize table got errno %d on %s.%s, retrying",
 
819
                      my_errno, param.db_name, param.table_name);
 
820
    param.testflag&= ~T_REP_BY_SORT;
 
821
    error= repair(session,param,1);
 
822
  }
 
823
  return error;
 
824
}
 
825
 
682
826
 
683
827
int ha_myisam::repair(Session *session, MI_CHECK &param, bool do_optimize)
684
828
{
700
844
  */
701
845
  if (file->dfile == -1)
702
846
  {
703
 
    errmsg_printf(error::INFO, "Retrying repair of: '%s' failed. "
704
 
                  "Please try REPAIR EXTENDED or myisamchk",
705
 
                  getTable()->getShare()->getPath());
 
847
    errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' failed. "
 
848
                          "Please try REPAIR EXTENDED or myisamchk",
 
849
                          table->s->path.str);
706
850
    return(HA_ADMIN_FAILED);
707
851
  }
708
852
 
709
 
  param.db_name=    getTable()->getShare()->getSchemaName();
710
 
  param.table_name= getTable()->getAlias();
 
853
  param.db_name=    table->s->db.str;
 
854
  param.table_name= table->alias;
711
855
  param.tmpfile_createflag = O_RDWR | O_TRUNC;
712
856
  param.using_global_keycache = 1;
713
857
  param.session= session;
714
858
  param.out_flag= 0;
715
 
  param.sort_buffer_length= static_cast<size_t>(sort_buffer_size);
 
859
  param.sort_buffer_length= (size_t)sort_buffer_size;
716
860
  strcpy(fixed_name,file->filename);
717
861
 
718
862
  // Don't lock tables if we have used LOCK Table
719
 
  if (mi_lock_database(file, getTable()->getShare()->getType() ? F_EXTRA_LCK : F_WRLCK))
 
863
  if (!session->locked_tables &&
 
864
      mi_lock_database(file, table->s->tmp_table ? F_EXTRA_LCK : F_WRLCK))
720
865
  {
721
 
    mi_check_print_error(&param,ER(ER_CANT_LOCK),errno);
 
866
    mi_check_print_error(&param,ER(ER_CANT_LOCK),my_errno);
722
867
    return(HA_ADMIN_FAILED);
723
868
  }
724
869
 
737
882
      local_testflag|= T_STATISTICS;
738
883
      param.testflag|= T_STATISTICS;            // We get this for free
739
884
      statistics_done=1;
 
885
      if (repair_threads > 1)
 
886
      {
 
887
        char buf[40];
 
888
        /* TODO: respect myisam_repair_threads variable */
 
889
        snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map));
 
890
        session->set_proc_info(buf);
 
891
        error = mi_repair_parallel(&param, file, fixed_name,
 
892
            param.testflag & T_QUICK);
 
893
        session->set_proc_info("Repair done"); // to reset proc_info, as
 
894
                                      // it was pointing to local buffer
 
895
      }
 
896
      else
740
897
      {
741
898
        session->set_proc_info("Repair by sorting");
742
899
        error = mi_repair_by_sort(&param, file, fixed_name,
802
959
    {
803
960
      char llbuff[22],llbuff2[22];
804
961
      mi_check_print_warning(&param,"Number of rows changed from %s to %s",
805
 
                             internal::llstr(rows,llbuff),
806
 
                             internal::llstr(file->state->records,llbuff2));
 
962
                             llstr(rows,llbuff),
 
963
                             llstr(file->state->records,llbuff2));
807
964
    }
808
965
  }
809
966
  else
813
970
    update_state_info(&param, file, 0);
814
971
  }
815
972
  session->set_proc_info(old_proc_info);
816
 
  mi_lock_database(file,F_UNLCK);
817
 
 
 
973
  if (!session->locked_tables)
 
974
    mi_lock_database(file,F_UNLCK);
818
975
  return(error ? HA_ADMIN_FAILED :
819
976
              !optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
820
977
}
821
978
 
822
979
 
823
980
/*
 
981
  Assign table indexes to a specific key cache.
 
982
*/
 
983
 
 
984
int ha_myisam::assign_to_keycache(Session* session, HA_CHECK_OPT *check_opt)
 
985
{
 
986
  KEY_CACHE *new_key_cache= check_opt->key_cache;
 
987
  const char *errmsg= 0;
 
988
  int error= HA_ADMIN_OK;
 
989
  uint64_t map;
 
990
  TableList *table_list= table->pos_in_table_list;
 
991
 
 
992
  table->keys_in_use_for_query.clear_all();
 
993
 
 
994
  if (table_list->process_index_hints(table))
 
995
    return(HA_ADMIN_FAILED);
 
996
  map= ~(uint64_t) 0;
 
997
  if (!table->keys_in_use_for_query.is_clear_all())
 
998
    /* use all keys if there's no list specified by the user through hints */
 
999
    map= table->keys_in_use_for_query.to_uint64_t();
 
1000
 
 
1001
  if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
 
1002
  {
 
1003
    char buf[STRING_BUFFER_USUAL_SIZE];
 
1004
    snprintf(buf, sizeof(buf),
 
1005
                "Failed to flush to index file (errno: %d)", error);
 
1006
    errmsg= buf;
 
1007
    error= HA_ADMIN_CORRUPT;
 
1008
  }
 
1009
 
 
1010
  if (error != HA_ADMIN_OK)
 
1011
  {
 
1012
    /* Send error to user */
 
1013
    MI_CHECK param;
 
1014
    myisamchk_init(&param);
 
1015
    param.session= session;
 
1016
    param.op_name=    "assign_to_keycache";
 
1017
    param.db_name=    table->s->db.str;
 
1018
    param.table_name= table->s->table_name.str;
 
1019
    param.testflag= 0;
 
1020
    mi_check_print_error(&param, errmsg);
 
1021
  }
 
1022
  return(error);
 
1023
}
 
1024
 
 
1025
 
 
1026
/*
824
1027
  Disable indexes, making it persistent if requested.
825
1028
 
826
1029
  SYNOPSIS
879
1082
    Enable indexes, which might have been disabled by disable_index() before.
880
1083
    The modes without _SAVE work only if both data and indexes are empty,
881
1084
    since the MyISAM repair would enable them persistently.
882
 
    To be sure in these cases, call Cursor::delete_all_rows() before.
 
1085
    To be sure in these cases, call handler::delete_all_rows() before.
883
1086
 
884
1087
  IMPLEMENTATION
885
1088
    HA_KEY_SWITCH_NONUNIQ       is not implemented.
913
1116
  }
914
1117
  else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
915
1118
  {
916
 
    Session *session= getTable()->in_use;
917
 
    boost::scoped_ptr<MI_CHECK> param_ap(new MI_CHECK);
918
 
    MI_CHECK &param= *param_ap.get();
 
1119
    Session *session=current_session;
 
1120
    MI_CHECK param;
919
1121
    const char *save_proc_info= session->get_proc_info();
920
1122
    session->set_proc_info("Creating index");
921
1123
    myisamchk_init(&param);
923
1125
    param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
924
1126
                     T_CREATE_MISSING_KEYS);
925
1127
    param.myf_rw&= ~MY_WAIT_IF_FULL;
926
 
    param.sort_buffer_length=  static_cast<size_t>(sort_buffer_size);
927
 
    param.stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
 
1128
    param.sort_buffer_length=  (size_t)sort_buffer_size;
 
1129
    param.stats_method= (enum_mi_stats_method)session->variables.myisam_stats_method;
928
1130
    if ((error= (repair(session,param,0) != HA_ADMIN_OK)) && param.retry_repair)
929
1131
    {
930
 
      errmsg_printf(error::WARN, "Warning: Enabling keys got errno %d on %s.%s, retrying",
931
 
                        errno, param.db_name, param.table_name);
 
1132
      errmsg_printf(ERRMSG_LVL_WARN, "Warning: Enabling keys got errno %d on %s.%s, retrying",
 
1133
                        my_errno, param.db_name, param.table_name);
932
1134
      /* Repairing by sort failed. Now try standard repair method. */
933
1135
      param.testflag&= ~(T_REP_BY_SORT | T_QUICK);
934
1136
      error= (repair(session,param,0) != HA_ADMIN_OK);
937
1139
        might have been set by the first repair. They can still be seen
938
1140
        with SHOW WARNINGS then.
939
1141
      */
940
 
      if (not error)
 
1142
      if (! error)
941
1143
        session->clear_error();
942
1144
    }
943
1145
    info(HA_STATUS_CONST);
990
1192
 
991
1193
void ha_myisam::start_bulk_insert(ha_rows rows)
992
1194
{
993
 
  Session *session= getTable()->in_use;
994
 
  ulong size= session->variables.read_buff_size;
 
1195
  Session *session= current_session;
 
1196
  ulong size= cmin(session->variables.read_buff_size,
 
1197
                  (ulong) (table->s->avg_row_length*rows));
995
1198
 
996
1199
  /* don't enable row cache if too few rows */
997
1200
  if (! rows || (rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE))
1017
1220
                          (size_t)session->variables.bulk_insert_buff_size,
1018
1221
                          rows);
1019
1222
    }
 
1223
 
 
1224
  return;
1020
1225
}
1021
1226
 
1022
1227
/*
1041
1246
}
1042
1247
 
1043
1248
 
1044
 
 
1045
 
int ha_myisam::doUpdateRecord(const unsigned char *old_data, unsigned char *new_data)
1046
 
{
 
1249
bool ha_myisam::check_and_repair(Session *session)
 
1250
{
 
1251
  int error=0;
 
1252
  int marked_crashed;
 
1253
  char *old_query;
 
1254
  uint32_t old_query_length;
 
1255
  HA_CHECK_OPT check_opt;
 
1256
 
 
1257
  check_opt.init();
 
1258
  check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
 
1259
  // Don't use quick if deleted rows
 
1260
  if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
 
1261
    check_opt.flags|=T_QUICK;
 
1262
  errmsg_printf(ERRMSG_LVL_WARN, "Checking table:   '%s'",table->s->path.str);
 
1263
 
 
1264
  old_query= session->query;
 
1265
  old_query_length= session->query_length;
 
1266
  pthread_mutex_lock(&LOCK_thread_count);
 
1267
  session->query=        table->s->table_name.str;
 
1268
  session->query_length= table->s->table_name.length;
 
1269
  pthread_mutex_unlock(&LOCK_thread_count);
 
1270
 
 
1271
  if ((marked_crashed= mi_is_crashed(file)) || check(session, &check_opt))
 
1272
  {
 
1273
    errmsg_printf(ERRMSG_LVL_WARN, "Recovering table: '%s'",table->s->path.str);
 
1274
    check_opt.flags=
 
1275
      ((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
 
1276
       (marked_crashed                             ? 0 : T_QUICK) |
 
1277
       (myisam_recover_options & HA_RECOVER_FORCE  ? 0 : T_SAFE_REPAIR) |
 
1278
       T_AUTO_REPAIR);
 
1279
    if (repair(session, &check_opt))
 
1280
      error=1;
 
1281
  }
 
1282
  pthread_mutex_lock(&LOCK_thread_count);
 
1283
  session->query= old_query;
 
1284
  session->query_length= old_query_length;
 
1285
  pthread_mutex_unlock(&LOCK_thread_count);
 
1286
  return(error);
 
1287
}
 
1288
 
 
1289
bool ha_myisam::is_crashed() const
 
1290
{
 
1291
  return (file->s->state.changed & STATE_CRASHED ||
 
1292
          (file->s->state.open_count));
 
1293
}
 
1294
 
 
1295
int ha_myisam::update_row(const unsigned char *old_data, unsigned char *new_data)
 
1296
{
 
1297
  ha_statistic_increment(&SSV::ha_update_count);
 
1298
  if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
 
1299
    table->timestamp_field->set_time();
1047
1300
  return mi_update(file,old_data,new_data);
1048
1301
}
1049
1302
 
1050
 
int ha_myisam::doDeleteRecord(const unsigned char *buf)
 
1303
int ha_myisam::delete_row(const unsigned char *buf)
1051
1304
{
 
1305
  ha_statistic_increment(&SSV::ha_delete_count);
1052
1306
  return mi_delete(file,buf);
1053
1307
}
1054
1308
 
1055
 
 
1056
 
int ha_myisam::doStartIndexScan(uint32_t idx, bool )
 
1309
#ifdef __cplusplus
 
1310
extern "C" {
 
1311
#endif
 
1312
 
 
1313
bool index_cond_func_myisam(void *arg)
 
1314
{
 
1315
  ha_myisam *h= (ha_myisam*)arg;
 
1316
  /*if (h->in_range_read)*/
 
1317
  if (h->end_range)
 
1318
  {
 
1319
    if (h->compare_key2(h->end_range) > 0)
 
1320
      return 2; /* caller should return HA_ERR_END_OF_FILE already */
 
1321
  }
 
1322
  return (bool)h->pushed_idx_cond->val_int();
 
1323
}
 
1324
 
 
1325
#ifdef __cplusplus
 
1326
}
 
1327
#endif
 
1328
 
 
1329
 
 
1330
int ha_myisam::index_init(uint32_t idx, bool )
1057
1331
{
1058
1332
  active_index=idx;
1059
1333
  //in_range_read= false;
 
1334
  if (pushed_idx_cond_keyno == idx)
 
1335
    mi_set_index_cond_func(file, index_cond_func_myisam, this);
1060
1336
  return 0;
1061
1337
}
1062
1338
 
1063
1339
 
1064
 
int ha_myisam::doEndIndexScan()
 
1340
int ha_myisam::index_end()
1065
1341
{
1066
1342
  active_index=MAX_KEY;
 
1343
  //pushed_idx_cond_keyno= MAX_KEY;
 
1344
  mi_set_index_cond_func(file, NULL, 0);
 
1345
  in_range_check_pushed_down= false;
 
1346
  ds_mrr.dsmrr_close();
1067
1347
  return 0;
1068
1348
}
1069
1349
 
1070
1350
 
 
1351
uint32_t ha_myisam::index_flags(uint32_t inx, uint32_t, bool) const
 
1352
{
 
1353
  return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ?
 
1354
          0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
 
1355
          HA_READ_ORDER | HA_KEYREAD_ONLY |
 
1356
          (keys_with_parts.is_set(inx)?0:HA_DO_INDEX_COND_PUSHDOWN));
 
1357
}
 
1358
 
 
1359
 
1071
1360
int ha_myisam::index_read_map(unsigned char *buf, const unsigned char *key,
1072
1361
                              key_part_map keypart_map,
1073
1362
                              enum ha_rkey_function find_flag)
1074
1363
{
1075
1364
  assert(inited==INDEX);
1076
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
1365
  ha_statistic_increment(&SSV::ha_read_key_count);
1077
1366
  int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
1078
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1367
  table->status=error ? STATUS_NOT_FOUND: 0;
1079
1368
  return error;
1080
1369
}
1081
1370
 
1083
1372
                                  key_part_map keypart_map,
1084
1373
                                  enum ha_rkey_function find_flag)
1085
1374
{
1086
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
1375
  ha_statistic_increment(&SSV::ha_read_key_count);
1087
1376
  int error=mi_rkey(file, buf, index, key, keypart_map, find_flag);
1088
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1377
  table->status=error ? STATUS_NOT_FOUND: 0;
1089
1378
  return error;
1090
1379
}
1091
1380
 
1093
1382
                                   key_part_map keypart_map)
1094
1383
{
1095
1384
  assert(inited==INDEX);
1096
 
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
1385
  ha_statistic_increment(&SSV::ha_read_key_count);
1097
1386
  int error=mi_rkey(file, buf, active_index, key, keypart_map,
1098
1387
                    HA_READ_PREFIX_LAST);
1099
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1388
  table->status=error ? STATUS_NOT_FOUND: 0;
1100
1389
  return(error);
1101
1390
}
1102
1391
 
1103
1392
int ha_myisam::index_next(unsigned char *buf)
1104
1393
{
1105
1394
  assert(inited==INDEX);
1106
 
  ha_statistic_increment(&system_status_var::ha_read_next_count);
 
1395
  ha_statistic_increment(&SSV::ha_read_next_count);
1107
1396
  int error=mi_rnext(file,buf,active_index);
1108
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1397
  table->status=error ? STATUS_NOT_FOUND: 0;
1109
1398
  return error;
1110
1399
}
1111
1400
 
1112
1401
int ha_myisam::index_prev(unsigned char *buf)
1113
1402
{
1114
1403
  assert(inited==INDEX);
1115
 
  ha_statistic_increment(&system_status_var::ha_read_prev_count);
 
1404
  ha_statistic_increment(&SSV::ha_read_prev_count);
1116
1405
  int error=mi_rprev(file,buf, active_index);
1117
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1406
  table->status=error ? STATUS_NOT_FOUND: 0;
1118
1407
  return error;
1119
1408
}
1120
1409
 
1121
1410
int ha_myisam::index_first(unsigned char *buf)
1122
1411
{
1123
1412
  assert(inited==INDEX);
1124
 
  ha_statistic_increment(&system_status_var::ha_read_first_count);
 
1413
  ha_statistic_increment(&SSV::ha_read_first_count);
1125
1414
  int error=mi_rfirst(file, buf, active_index);
1126
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1415
  table->status=error ? STATUS_NOT_FOUND: 0;
1127
1416
  return error;
1128
1417
}
1129
1418
 
1130
1419
int ha_myisam::index_last(unsigned char *buf)
1131
1420
{
1132
1421
  assert(inited==INDEX);
1133
 
  ha_statistic_increment(&system_status_var::ha_read_last_count);
 
1422
  ha_statistic_increment(&SSV::ha_read_last_count);
1134
1423
  int error=mi_rlast(file, buf, active_index);
1135
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1424
  table->status=error ? STATUS_NOT_FOUND: 0;
1136
1425
  return error;
1137
1426
}
1138
1427
 
1142
1431
{
1143
1432
  int error;
1144
1433
  assert(inited==INDEX);
1145
 
  ha_statistic_increment(&system_status_var::ha_read_next_count);
 
1434
  ha_statistic_increment(&SSV::ha_read_next_count);
1146
1435
  do
1147
1436
  {
1148
1437
    error= mi_rnext_same(file,buf);
1149
1438
  } while (error == HA_ERR_RECORD_DELETED);
1150
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1439
  table->status=error ? STATUS_NOT_FOUND: 0;
1151
1440
  return error;
1152
1441
}
1153
1442
 
1160
1449
  //if (!eq_range_arg)
1161
1450
  //  in_range_read= true;
1162
1451
 
1163
 
  res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
 
1452
  res= handler::read_range_first(start_key, end_key, eq_range_arg, sorted);
1164
1453
 
1165
1454
  //if (res)
1166
1455
  //  in_range_read= false;
1170
1459
 
1171
1460
int ha_myisam::read_range_next()
1172
1461
{
1173
 
  int res= Cursor::read_range_next();
 
1462
  int res= handler::read_range_next();
1174
1463
  //if (res)
1175
1464
  //  in_range_read= false;
1176
1465
  return res;
1177
1466
}
1178
1467
 
1179
1468
 
1180
 
int ha_myisam::doStartTableScan(bool scan)
 
1469
int ha_myisam::rnd_init(bool scan)
1181
1470
{
1182
1471
  if (scan)
1183
1472
    return mi_scan_init(file);
1186
1475
 
1187
1476
int ha_myisam::rnd_next(unsigned char *buf)
1188
1477
{
1189
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
 
1478
  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
1190
1479
  int error=mi_scan(file, buf);
1191
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1480
  table->status=error ? STATUS_NOT_FOUND: 0;
1192
1481
  return error;
1193
1482
}
1194
1483
 
 
1484
int ha_myisam::restart_rnd_next(unsigned char *buf, unsigned char *pos)
 
1485
{
 
1486
  return rnd_pos(buf,pos);
 
1487
}
 
1488
 
1195
1489
int ha_myisam::rnd_pos(unsigned char *buf, unsigned char *pos)
1196
1490
{
1197
 
  ha_statistic_increment(&system_status_var::ha_read_rnd_count);
1198
 
  int error=mi_rrnd(file, buf, internal::my_get_ptr(pos,ref_length));
1199
 
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1491
  ha_statistic_increment(&SSV::ha_read_rnd_count);
 
1492
  int error=mi_rrnd(file, buf, my_get_ptr(pos,ref_length));
 
1493
  table->status=error ? STATUS_NOT_FOUND: 0;
1200
1494
  return error;
1201
1495
}
1202
1496
 
1203
1497
 
1204
1498
void ha_myisam::position(const unsigned char *)
1205
1499
{
1206
 
  internal::my_off_t row_position= mi_position(file);
1207
 
  internal::my_store_ptr(ref, ref_length, row_position);
 
1500
  my_off_t row_position= mi_position(file);
 
1501
  my_store_ptr(ref, ref_length, row_position);
1208
1502
}
1209
1503
 
1210
1504
int ha_myisam::info(uint32_t flag)
1225
1519
  }
1226
1520
  if (flag & HA_STATUS_CONST)
1227
1521
  {
1228
 
    TableShare *share= getTable()->getMutableShare();
 
1522
    TABLE_SHARE *share= table->s;
1229
1523
    stats.max_data_file_length=  misam_info.max_data_file_length;
1230
1524
    stats.max_index_file_length= misam_info.max_index_file_length;
1231
1525
    stats.create_time= misam_info.create_time;
1232
1526
    ref_length= misam_info.reflength;
1233
1527
    share->db_options_in_use= misam_info.options;
1234
 
    stats.block_size= myisam_key_cache_block_size;        /* record block size */
 
1528
    stats.block_size= block_size;        /* record block size */
1235
1529
 
1236
 
    set_prefix(share->keys_in_use, share->sizeKeys());
1237
 
    /*
1238
 
     * Due to bug 394932 (32-bit solaris build failure), we need
1239
 
     * to convert the uint64_t key_map member of the misam_info
1240
 
     * structure in to a std::bitset so that we can logically and
1241
 
     * it with the share->key_in_use key_map.
1242
 
     */
1243
 
    ostringstream ostr;
1244
 
    string binary_key_map;
1245
 
    uint64_t num= misam_info.key_map;
1246
 
    /*
1247
 
     * Convert the uint64_t to a binary
1248
 
     * string representation of it.
1249
 
     */
1250
 
    while (num > 0)
1251
 
    {
1252
 
      uint64_t bin_digit= num % 2;
1253
 
      ostr << bin_digit;
1254
 
      num/= 2;
1255
 
    }
1256
 
    binary_key_map.append(ostr.str());
1257
 
    /*
1258
 
     * Now we have the binary string representation of the
1259
 
     * flags, we need to fill that string representation out
1260
 
     * with the appropriate number of bits. This is needed
1261
 
     * since key_map is declared as a std::bitset of a certain bit
1262
 
     * width that depends on the MAX_INDEXES variable. 
1263
 
     */
1264
 
    if (MAX_INDEXES <= 64)
1265
 
    {
1266
 
      size_t len= 72 - binary_key_map.length();
1267
 
      string all_zeros(len, '0');
1268
 
      binary_key_map.insert(binary_key_map.begin(),
1269
 
                            all_zeros.begin(),
1270
 
                            all_zeros.end());
1271
 
    }
1272
 
    else
1273
 
    {
1274
 
      size_t len= (MAX_INDEXES + 7) / 8 * 8;
1275
 
      string all_zeros(len, '0');
1276
 
      binary_key_map.insert(binary_key_map.begin(),
1277
 
                            all_zeros.begin(),
1278
 
                            all_zeros.end());
1279
 
    }
1280
 
    key_map tmp_map(binary_key_map);
1281
 
    share->keys_in_use&= tmp_map;
1282
 
    share->keys_for_keyread&= share->keys_in_use;
 
1530
    /* Update share */
 
1531
    if (share->tmp_table == NO_TMP_TABLE)
 
1532
      pthread_mutex_lock(&share->mutex);
 
1533
    share->keys_in_use.set_prefix(share->keys);
 
1534
    share->keys_in_use.intersect_extended(misam_info.key_map);
 
1535
    share->keys_for_keyread.intersect(share->keys_in_use);
1283
1536
    share->db_record_offset= misam_info.record_offset;
1284
1537
    if (share->key_parts)
1285
 
      memcpy(getTable()->key_info[0].rec_per_key,
 
1538
      memcpy(table->key_info[0].rec_per_key,
1286
1539
             misam_info.rec_per_key,
1287
 
             sizeof(getTable()->key_info[0].rec_per_key)*share->key_parts);
1288
 
    assert(share->getType() != message::Table::STANDARD);
 
1540
             sizeof(table->key_info[0].rec_per_key)*share->key_parts);
 
1541
    if (share->tmp_table == NO_TMP_TABLE)
 
1542
      pthread_mutex_unlock(&share->mutex);
1289
1543
 
1290
1544
   /*
1291
1545
     Set data_file_name and index_file_name to point at the symlink value
1292
1546
     if table is symlinked (Ie;  Real name is not same as generated name)
1293
1547
   */
1294
1548
    data_file_name= index_file_name= 0;
1295
 
    internal::fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
 
1549
    fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
1296
1550
              MY_APPEND_EXT | MY_UNPACK_FILENAME);
1297
1551
    if (strcmp(name_buff, misam_info.data_file_name))
1298
1552
      data_file_name=misam_info.data_file_name;
1299
 
    internal::fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
 
1553
    fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
1300
1554
              MY_APPEND_EXT | MY_UNPACK_FILENAME);
1301
1555
    if (strcmp(name_buff, misam_info.index_file_name))
1302
1556
      index_file_name=misam_info.index_file_name;
1304
1558
  if (flag & HA_STATUS_ERRKEY)
1305
1559
  {
1306
1560
    errkey  = misam_info.errkey;
1307
 
    internal::my_store_ptr(dup_ref, ref_length, misam_info.dupp_key_pos);
 
1561
    my_store_ptr(dup_ref, ref_length, misam_info.dupp_key_pos);
1308
1562
  }
1309
1563
  if (flag & HA_STATUS_TIME)
1310
1564
    stats.update_time = misam_info.update_time;
1322
1576
 
1323
1577
int ha_myisam::reset(void)
1324
1578
{
 
1579
  pushed_idx_cond= NULL;
 
1580
  pushed_idx_cond_keyno= MAX_KEY;
 
1581
  mi_set_index_cond_func(file, NULL, 0);
 
1582
  ds_mrr.dsmrr_close();
1325
1583
  return mi_reset(file);
1326
1584
}
1327
1585
 
1337
1595
  return mi_delete_all_rows(file);
1338
1596
}
1339
1597
 
1340
 
int MyisamEngine::doDropTable(Session &session,
1341
 
                              const identifier::Table &identifier)
 
1598
int ha_myisam::delete_table(const char *name)
1342
1599
{
1343
 
  session.getMessageCache().removeTableMessage(identifier);
1344
 
 
1345
 
  return mi_delete_table(identifier.getPath().c_str());
 
1600
  return mi_delete_table(name);
1346
1601
}
1347
1602
 
1348
1603
 
1349
1604
int ha_myisam::external_lock(Session *session, int lock_type)
1350
1605
{
1351
 
  file->in_use= session;
1352
 
  return mi_lock_database(file, !getTable()->getShare()->getType() ?
 
1606
  file->in_use.data= session;
 
1607
  return mi_lock_database(file, !table->s->tmp_table ?
1353
1608
                          lock_type : ((lock_type == F_UNLCK) ?
1354
1609
                                       F_UNLCK : F_EXTRA_LCK));
1355
1610
}
1356
1611
 
1357
 
int MyisamEngine::doCreateTable(Session &session,
1358
 
                                Table& table_arg,
1359
 
                                const identifier::Table &identifier,
1360
 
                                message::Table& create_proto)
 
1612
THR_LOCK_DATA **ha_myisam::store_lock(Session *,
 
1613
                                      THR_LOCK_DATA **to,
 
1614
                                      enum thr_lock_type lock_type)
 
1615
{
 
1616
  if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK)
 
1617
    file->lock.type=lock_type;
 
1618
  *to++= &file->lock;
 
1619
  return to;
 
1620
}
 
1621
 
 
1622
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
 
1623
{
 
1624
  ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
 
1625
  if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
 
1626
  {
 
1627
    create_info->auto_increment_value= stats.auto_increment_value;
 
1628
  }
 
1629
  create_info->data_file_name=data_file_name;
 
1630
  create_info->index_file_name=index_file_name;
 
1631
}
 
1632
 
 
1633
 
 
1634
int ha_myisam::create(const char *name, register Table *table_arg,
 
1635
                      HA_CREATE_INFO *ha_create_info)
1361
1636
{
1362
1637
  int error;
1363
1638
  uint32_t create_flags= 0, create_records;
1365
1640
  MI_KEYDEF *keydef;
1366
1641
  MI_COLUMNDEF *recinfo;
1367
1642
  MI_CREATE_INFO create_info;
1368
 
  TableShare *share= table_arg.getMutableShare();
 
1643
  TABLE_SHARE *share= table_arg->s;
1369
1644
  uint32_t options= share->db_options_in_use;
1370
 
  if ((error= table2myisam(&table_arg, &keydef, &recinfo, &create_records)))
1371
 
    return(error);
 
1645
  if ((error= table2myisam(table_arg, &keydef, &recinfo, &create_records)))
 
1646
    return(error); /* purecov: inspected */
1372
1647
  memset(&create_info, 0, sizeof(create_info));
1373
 
  create_info.max_rows= create_proto.options().max_rows();
1374
 
  create_info.reloc_rows= create_proto.options().min_rows();
 
1648
  create_info.max_rows= share->max_rows;
 
1649
  create_info.reloc_rows= share->min_rows;
1375
1650
  create_info.with_auto_increment= share->next_number_key_offset == 0;
1376
 
  create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
1377
 
                               create_proto.options().auto_increment_value() -1 :
 
1651
  create_info.auto_increment= (ha_create_info->auto_increment_value ?
 
1652
                               ha_create_info->auto_increment_value -1 :
1378
1653
                               (uint64_t) 0);
1379
 
  create_info.data_file_length= (create_proto.options().max_rows() *
1380
 
                                 create_proto.options().avg_row_length());
1381
 
  create_info.data_file_name= NULL;
1382
 
  create_info.index_file_name=  NULL;
 
1654
  create_info.data_file_length= ((uint64_t) share->max_rows *
 
1655
                                 share->avg_row_length);
 
1656
  create_info.data_file_name= ha_create_info->data_file_name;
 
1657
  create_info.index_file_name= ha_create_info->index_file_name;
1383
1658
  create_info.language= share->table_charset->number;
1384
1659
 
1385
 
  if (create_proto.type() == message::Table::TEMPORARY)
 
1660
  if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
1386
1661
    create_flags|= HA_CREATE_TMP_TABLE;
 
1662
  if (ha_create_info->options & HA_CREATE_KEEP_FILES)
 
1663
    create_flags|= HA_CREATE_KEEP_FILES;
1387
1664
  if (options & HA_OPTION_PACK_RECORD)
1388
1665
    create_flags|= HA_PACK_RECORD;
 
1666
  if (options & HA_OPTION_CHECKSUM)
 
1667
    create_flags|= HA_CREATE_CHECKSUM;
 
1668
  if (options & HA_OPTION_DELAY_KEY_WRITE)
 
1669
    create_flags|= HA_CREATE_DELAY_KEY_WRITE;
1389
1670
 
1390
 
  /* TODO: Check that the following internal::fn_format is really needed */
1391
 
  error= mi_create(internal::fn_format(buff, identifier.getPath().c_str(), "", "",
1392
 
                                       MY_UNPACK_FILENAME|MY_APPEND_EXT),
1393
 
                   share->sizeKeys(), keydef,
 
1671
  /* TODO: Check that the following fn_format is really needed */
 
1672
  error= mi_create(fn_format(buff, name, "", "",
 
1673
                             MY_UNPACK_FILENAME|MY_APPEND_EXT),
 
1674
                   share->keys, keydef,
1394
1675
                   create_records, recinfo,
1395
1676
                   0, (MI_UNIQUEDEF*) 0,
1396
1677
                   &create_info, create_flags);
1397
1678
  free((unsigned char*) recinfo);
1398
 
 
1399
 
  session.getMessageCache().storeTableMessage(identifier, create_proto);
1400
 
 
1401
 
  return error;
 
1679
  return(error);
1402
1680
}
1403
1681
 
1404
1682
 
1405
 
int MyisamEngine::doRenameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
 
1683
int ha_myisam::rename_table(const char * from, const char * to)
1406
1684
{
1407
 
  session.getMessageCache().renameTableMessage(from, to);
1408
 
 
1409
 
  return mi_rename(from.getPath().c_str(), to.getPath().c_str());
 
1685
  return mi_rename(from,to);
1410
1686
}
1411
1687
 
1412
1688
 
1420
1696
  int error;
1421
1697
  unsigned char key[MI_MAX_KEY_LENGTH];
1422
1698
 
1423
 
  if (!getTable()->getShare()->next_number_key_offset)
 
1699
  if (!table->s->next_number_key_offset)
1424
1700
  {                                             // Autoincrement at key-start
1425
1701
    ha_myisam::info(HA_STATUS_AUTO);
1426
1702
    *first_value= stats.auto_increment_value;
1430
1706
  }
1431
1707
 
1432
1708
  /* it's safe to call the following if bulk_insert isn't on */
1433
 
  mi_flush_bulk_insert(file, getTable()->getShare()->next_number_index);
 
1709
  mi_flush_bulk_insert(file, table->s->next_number_index);
1434
1710
 
1435
1711
  (void) extra(HA_EXTRA_KEYREAD);
1436
 
  key_copy(key, getTable()->getInsertRecord(),
1437
 
           &getTable()->key_info[getTable()->getShare()->next_number_index],
1438
 
           getTable()->getShare()->next_number_key_offset);
1439
 
  error= mi_rkey(file, getTable()->getUpdateRecord(), (int) getTable()->getShare()->next_number_index,
1440
 
                 key, make_prev_keypart_map(getTable()->getShare()->next_number_keypart),
 
1712
  key_copy(key, table->record[0],
 
1713
           table->key_info + table->s->next_number_index,
 
1714
           table->s->next_number_key_offset);
 
1715
  error= mi_rkey(file, table->record[1], (int) table->s->next_number_index,
 
1716
                 key, make_prev_keypart_map(table->s->next_number_keypart),
1441
1717
                 HA_READ_PREFIX_LAST);
1442
1718
  if (error)
1443
1719
    nr= 1;
1444
1720
  else
1445
1721
  {
1446
 
    /* Get data from getUpdateRecord() */
1447
 
    nr= ((uint64_t) getTable()->next_number_field->
1448
 
         val_int_offset(getTable()->getShare()->rec_buff_length)+1);
 
1722
    /* Get data from record[1] */
 
1723
    nr= ((uint64_t) table->next_number_field->
 
1724
         val_int_offset(table->s->rec_buff_length)+1);
1449
1725
  }
1450
1726
  extra(HA_EXTRA_NO_KEYREAD);
1451
1727
  *first_value= nr;
1496
1772
  return (uint)file->state->checksum;
1497
1773
}
1498
1774
 
1499
 
static int myisam_init(module::Context &context)
1500
 
1501
 
  context.add(new MyisamEngine(engine_name));
1502
 
  context.registerVariable(new sys_var_constrained_value<size_t>("sort-buffer-size",
1503
 
                                                                 sort_buffer_size));
1504
 
  context.registerVariable(new sys_var_uint64_t_ptr("max_sort_file_size",
1505
 
                                                    &max_sort_file_size,
1506
 
                                                    context.getOptions()["max-sort-file-size"].as<uint64_t>()));
1507
 
 
 
1775
 
 
1776
bool ha_myisam::check_if_incompatible_data(HA_CREATE_INFO *create_info,
 
1777
                                           uint32_t table_changes)
 
1778
{
 
1779
  uint32_t options= table->s->db_options_in_use;
 
1780
 
 
1781
  if (create_info->auto_increment_value != stats.auto_increment_value ||
 
1782
      create_info->data_file_name != data_file_name ||
 
1783
      create_info->index_file_name != index_file_name ||
 
1784
      table_changes == IS_EQUAL_NO ||
 
1785
      table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet
 
1786
    return COMPATIBLE_DATA_NO;
 
1787
 
 
1788
  if ((options & (HA_OPTION_PACK_RECORD | HA_OPTION_CHECKSUM |
 
1789
                  HA_OPTION_DELAY_KEY_WRITE)) !=
 
1790
      (create_info->table_options & (HA_OPTION_PACK_RECORD |
 
1791
                                     HA_OPTION_CHECKSUM |
 
1792
                              HA_OPTION_DELAY_KEY_WRITE)))
 
1793
    return COMPATIBLE_DATA_NO;
 
1794
  return COMPATIBLE_DATA_YES;
 
1795
}
 
1796
 
 
1797
int myisam_deinit(void *)
 
1798
{
 
1799
  pthread_mutex_destroy(&THR_LOCK_myisam);
 
1800
 
 
1801
  return mi_panic(HA_PANIC_CLOSE);
 
1802
}
 
1803
 
 
1804
static int myisam_init(void *p)
 
1805
{
 
1806
  myisam_hton= (handlerton *)p;
 
1807
  myisam_hton->state= SHOW_OPTION_YES;
 
1808
  myisam_hton->create= myisam_create_handler;
 
1809
  myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
1508
1810
  return 0;
1509
1811
}
1510
1812
 
1511
1813
 
1512
 
static void init_options(drizzled::module::option_context &context)
1513
 
{
1514
 
  context("max-sort-file-size",
1515
 
          po::value<uint64_t>(&max_sort_file_size)->default_value(INT32_MAX),
1516
 
          _("Don't use the fast sort index method to created index if the temporary file would get bigger than this."));
1517
 
  context("sort-buffer-size",
1518
 
          po::value<sort_buffer_constraint>(&sort_buffer_size)->default_value(8192*1024),
1519
 
          _("The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE."));
1520
 
}
1521
 
 
1522
 
 
1523
 
DRIZZLE_DECLARE_PLUGIN
1524
 
{
1525
 
  DRIZZLE_VERSION_ID,
 
1814
 
 
1815
/****************************************************************************
 
1816
 * MyISAM MRR implementation: use DS-MRR
 
1817
 ***************************************************************************/
 
1818
 
 
1819
int ha_myisam::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
 
1820
                                     uint32_t n_ranges, uint32_t mode,
 
1821
                                     HANDLER_BUFFER *buf)
 
1822
{
 
1823
  return ds_mrr.dsmrr_init(this, &table->key_info[active_index],
 
1824
                           seq, seq_init_param, n_ranges, mode, buf);
 
1825
}
 
1826
 
 
1827
int ha_myisam::multi_range_read_next(char **range_info)
 
1828
{
 
1829
  return ds_mrr.dsmrr_next(this, range_info);
 
1830
}
 
1831
 
 
1832
ha_rows ha_myisam::multi_range_read_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
 
1833
                                               void *seq_init_param,
 
1834
                                               uint32_t n_ranges, uint32_t *bufsz,
 
1835
                                               uint32_t *flags, COST_VECT *cost)
 
1836
{
 
1837
  /*
 
1838
    This call is here because there is no location where this->table would
 
1839
    already be known.
 
1840
    TODO: consider moving it into some per-query initialization call.
 
1841
  */
 
1842
  ds_mrr.init(this, table);
 
1843
  return ds_mrr.dsmrr_info_const(keyno, seq, seq_init_param, n_ranges, bufsz,
 
1844
                                 flags, cost);
 
1845
}
 
1846
 
 
1847
int ha_myisam::multi_range_read_info(uint32_t keyno, uint32_t n_ranges, uint32_t keys,
 
1848
                                     uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
 
1849
{
 
1850
  ds_mrr.init(this, table);
 
1851
  return ds_mrr.dsmrr_info(keyno, n_ranges, keys, bufsz, flags, cost);
 
1852
}
 
1853
 
 
1854
/* MyISAM MRR implementation ends */
 
1855
 
 
1856
 
 
1857
/* Index condition pushdown implementation*/
 
1858
 
 
1859
 
 
1860
Item *ha_myisam::idx_cond_push(uint32_t keyno_arg, Item* idx_cond_arg)
 
1861
{
 
1862
  pushed_idx_cond_keyno= keyno_arg;
 
1863
  pushed_idx_cond= idx_cond_arg;
 
1864
  in_range_check_pushed_down= true;
 
1865
  if (active_index == pushed_idx_cond_keyno)
 
1866
    mi_set_index_cond_func(file, index_cond_func_myisam, this);
 
1867
  return NULL;
 
1868
}
 
1869
 
 
1870
static DRIZZLE_SYSVAR_UINT(block_size, block_size,
 
1871
                           PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
 
1872
                           N_("Block size to be used for MyISAM index pages."),
 
1873
                           NULL, NULL, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH, 
 
1874
                           MI_MAX_KEY_BLOCK_LENGTH, 0);
 
1875
 
 
1876
static DRIZZLE_SYSVAR_UINT(repair_threads, repair_threads,
 
1877
                           PLUGIN_VAR_RQCMDARG,
 
1878
                           N_("Number of threads to use when repairing MyISAM tables. The value of "
 
1879
                              "1 disables parallel repair."),
 
1880
                           NULL, NULL, 1, 1, UINT32_MAX, 0);
 
1881
 
 
1882
static DRIZZLE_SYSVAR_ULONGLONG(max_sort_file_size, max_sort_file_size,
 
1883
                                PLUGIN_VAR_RQCMDARG,
 
1884
                                N_("Don't use the fast sort index method to created index if the temporary file would get bigger than this."),
 
1885
                                NULL, NULL, INT32_MAX, 0, UINT64_MAX, 0);
 
1886
 
 
1887
static DRIZZLE_SYSVAR_ULONGLONG(sort_buffer_size, sort_buffer_size,
 
1888
                                PLUGIN_VAR_RQCMDARG,
 
1889
                                N_("The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE."),
 
1890
                                NULL, NULL, 8192*1024, 1024, SIZE_MAX, 0);
 
1891
 
 
1892
extern uint32_t data_pointer_size;
 
1893
static DRIZZLE_SYSVAR_UINT(data_pointer_size, data_pointer_size,
 
1894
                           PLUGIN_VAR_RQCMDARG,
 
1895
                           N_("Default pointer size to be used for MyISAM tables."),
 
1896
                           NULL, NULL, 6, 2, 7, 0);
 
1897
 
 
1898
static struct st_mysql_sys_var* system_variables[]= {
 
1899
  DRIZZLE_SYSVAR(block_size),
 
1900
  DRIZZLE_SYSVAR(repair_threads),
 
1901
  DRIZZLE_SYSVAR(max_sort_file_size),
 
1902
  DRIZZLE_SYSVAR(sort_buffer_size),
 
1903
  DRIZZLE_SYSVAR(data_pointer_size),
 
1904
  NULL
 
1905
};
 
1906
 
 
1907
 
 
1908
drizzle_declare_plugin(myisam)
 
1909
{
 
1910
  DRIZZLE_STORAGE_ENGINE_PLUGIN,
1526
1911
  "MyISAM",
1527
 
  "2.0",
 
1912
  "1.0",
1528
1913
  "MySQL AB",
1529
1914
  "Default engine as of MySQL 3.23 with great performance",
1530
1915
  PLUGIN_LICENSE_GPL,
1531
1916
  myisam_init, /* Plugin Init */
1532
 
  NULL,           /* depends */
1533
 
  init_options                        /* config options                  */
 
1917
  myisam_deinit, /* Plugin Deinit */
 
1918
  NULL,                       /* status variables                */
 
1919
  system_variables,           /* system variables */
 
1920
  NULL                        /* config options                  */
1534
1921
}
1535
 
DRIZZLE_DECLARE_PLUGIN_END;
 
1922
drizzle_declare_plugin_end;