~xnox/ubuntu/saucy/drizzle/merge

« back to all changes in this revision

Viewing changes to .pc/debian-changes-2010.12.06-0ubuntu4/plugin/myisam/ha_myisam.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2011-01-01 13:55:03 UTC
  • Revision ID: james.westby@ubuntu.com-20110101135503-x2ub1akxoisgwi6z
Tags: 2010.12.06-0ubuntu4
* Fixed missing build depends.
* Added Lee to uploaders.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2006 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; version 2 of the License.
 
6
 
 
7
   This program is distributed in the hope that it will be useful,
 
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
10
   GNU General Public License for more details.
 
11
 
 
12
   You should have received a copy of the GNU General Public License
 
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"
 
20
#include "myisampack.h"
 
21
#include "ha_myisam.h"
 
22
#include "myisam_priv.h"
 
23
#include "drizzled/option.h"
 
24
#include "drizzled/internal/my_bit.h"
 
25
#include "drizzled/internal/m_string.h"
 
26
#include "drizzled/util/test.h"
 
27
#include "drizzled/error.h"
 
28
#include "drizzled/errmsg_print.h"
 
29
#include "drizzled/gettext.h"
 
30
#include "drizzled/session.h"
 
31
#include "drizzled/plugin.h"
 
32
#include "drizzled/plugin/client.h"
 
33
#include "drizzled/table.h"
 
34
#include "drizzled/field/timestamp.h"
 
35
#include "drizzled/memory/multi_malloc.h"
 
36
#include "drizzled/plugin/daemon.h"
 
37
 
 
38
#include <boost/algorithm/string.hpp>
 
39
#include <boost/scoped_ptr.hpp>
 
40
 
 
41
#include <string>
 
42
#include <sstream>
 
43
#include <map>
 
44
#include <algorithm>
 
45
#include <memory>
 
46
#include <boost/program_options.hpp>
 
47
#include <drizzled/module/option_map.h>
 
48
 
 
49
namespace po= boost::program_options;
 
50
 
 
51
using namespace std;
 
52
using namespace drizzled;
 
53
 
 
54
static const string engine_name("MyISAM");
 
55
 
 
56
boost::mutex THR_LOCK_myisam;
 
57
 
 
58
static uint32_t myisam_key_cache_block_size= KEY_CACHE_BLOCK_SIZE;
 
59
static uint32_t myisam_key_cache_size;
 
60
static uint32_t myisam_key_cache_division_limit;
 
61
static uint32_t myisam_key_cache_age_threshold;
 
62
static uint64_t max_sort_file_size;
 
63
typedef constrained_check<size_t, SIZE_MAX, 1024, 1024> sort_buffer_constraint;
 
64
static sort_buffer_constraint sort_buffer_size;
 
65
 
 
66
void st_mi_isam_share::setKeyCache()
 
67
{
 
68
  (void)init_key_cache(&key_cache,
 
69
                       myisam_key_cache_block_size,
 
70
                       myisam_key_cache_size,
 
71
                       myisam_key_cache_division_limit, 
 
72
                       myisam_key_cache_age_threshold);
 
73
}
 
74
 
 
75
/*****************************************************************************
 
76
** MyISAM tables
 
77
*****************************************************************************/
 
78
 
 
79
static const char *ha_myisam_exts[] = {
 
80
  ".MYI",
 
81
  ".MYD",
 
82
  NULL
 
83
};
 
84
 
 
85
class MyisamEngine : public plugin::StorageEngine
 
86
{
 
87
  MyisamEngine();
 
88
  MyisamEngine(const MyisamEngine&);
 
89
  MyisamEngine& operator=(const MyisamEngine&);
 
90
public:
 
91
  explicit MyisamEngine(string name_arg) :
 
92
    plugin::StorageEngine(name_arg,
 
93
                          HTON_CAN_INDEX_BLOBS |
 
94
                          HTON_STATS_RECORDS_IS_EXACT |
 
95
                          HTON_TEMPORARY_ONLY |
 
96
                          HTON_NULL_IN_KEY |
 
97
                          HTON_HAS_RECORDS |
 
98
                          HTON_DUPLICATE_POS |
 
99
                          HTON_AUTO_PART_KEY |
 
100
                          HTON_SKIP_STORE_LOCK)
 
101
  {
 
102
  }
 
103
 
 
104
  virtual ~MyisamEngine()
 
105
  { 
 
106
    mi_panic(HA_PANIC_CLOSE);
 
107
  }
 
108
 
 
109
  virtual Cursor *create(Table &table)
 
110
  {
 
111
    return new ha_myisam(*this, table);
 
112
  }
 
113
 
 
114
  const char **bas_ext() const {
 
115
    return ha_myisam_exts;
 
116
  }
 
117
 
 
118
  int doCreateTable(Session&,
 
119
                    Table& table_arg,
 
120
                    const TableIdentifier &identifier,
 
121
                    message::Table&);
 
122
 
 
123
  int doRenameTable(Session&, const TableIdentifier &from, const TableIdentifier &to);
 
124
 
 
125
  int doDropTable(Session&, const TableIdentifier &identifier);
 
126
 
 
127
  int doGetTableDefinition(Session& session,
 
128
                           const TableIdentifier &identifier,
 
129
                           message::Table &table_message);
 
130
 
 
131
  uint32_t max_supported_keys()          const { return MI_MAX_KEY; }
 
132
  uint32_t max_supported_key_length()    const { return MI_MAX_KEY_LENGTH; }
 
133
  uint32_t max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
 
134
 
 
135
  uint32_t index_flags(enum  ha_key_alg) const
 
136
  {
 
137
    return (HA_READ_NEXT |
 
138
            HA_READ_PREV |
 
139
            HA_READ_RANGE |
 
140
            HA_READ_ORDER |
 
141
            HA_KEYREAD_ONLY);
 
142
  }
 
143
  bool doDoesTableExist(Session& session, const TableIdentifier &identifier);
 
144
 
 
145
  void doGetTableIdentifiers(drizzled::CachedDirectory &directory,
 
146
                             const drizzled::SchemaIdentifier &schema_identifier,
 
147
                             drizzled::TableIdentifier::vector &set_of_identifiers);
 
148
  bool validateCreateTableOption(const std::string &key, const std::string &state)
 
149
  {
 
150
    (void)state;
 
151
    if (boost::iequals(key, "ROW_FORMAT"))
 
152
    {
 
153
      return true;
 
154
    }
 
155
 
 
156
    return false;
 
157
  }
 
158
};
 
159
 
 
160
void MyisamEngine::doGetTableIdentifiers(drizzled::CachedDirectory&,
 
161
                                         const drizzled::SchemaIdentifier&,
 
162
                                         drizzled::TableIdentifier::vector&)
 
163
{
 
164
}
 
165
 
 
166
bool MyisamEngine::doDoesTableExist(Session &session, const TableIdentifier &identifier)
 
167
{
 
168
  return session.getMessageCache().doesTableMessageExist(identifier);
 
169
}
 
170
 
 
171
int MyisamEngine::doGetTableDefinition(Session &session,
 
172
                                       const TableIdentifier &identifier,
 
173
                                       message::Table &table_message)
 
174
{
 
175
  if (session.getMessageCache().getTableMessage(identifier, table_message))
 
176
    return EEXIST;
 
177
  return ENOENT;
 
178
}
 
179
 
 
180
/* 
 
181
  Convert to push_Warnings if you ever care about this, otherwise, it is a no-op.
 
182
*/
 
183
 
 
184
static void mi_check_print_msg(MI_CHECK *,      const char* ,
 
185
                               const char *, va_list )
 
186
{
 
187
}
 
188
 
 
189
 
 
190
/*
 
191
  Convert Table object to MyISAM key and column definition
 
192
 
 
193
  SYNOPSIS
 
194
    table2myisam()
 
195
      table_arg   in     Table object.
 
196
      keydef_out  out    MyISAM key definition.
 
197
      recinfo_out out    MyISAM column definition.
 
198
      records_out out    Number of fields.
 
199
 
 
200
  DESCRIPTION
 
201
    This function will allocate and initialize MyISAM key and column
 
202
    definition for further use in mi_create or for a check for underlying
 
203
    table conformance in merge engine.
 
204
 
 
205
    The caller needs to free *recinfo_out after use. Since *recinfo_out
 
206
    and *keydef_out are allocated with a multi_malloc, *keydef_out
 
207
    is freed automatically when *recinfo_out is freed.
 
208
 
 
209
  RETURN VALUE
 
210
    0  OK
 
211
    !0 error code
 
212
*/
 
213
 
 
214
static int table2myisam(Table *table_arg, MI_KEYDEF **keydef_out,
 
215
                        MI_COLUMNDEF **recinfo_out, uint32_t *records_out)
 
216
{
 
217
  uint32_t i, j, recpos, minpos, fieldpos, temp_length, length;
 
218
  enum ha_base_keytype type= HA_KEYTYPE_BINARY;
 
219
  unsigned char *record;
 
220
  MI_KEYDEF *keydef;
 
221
  MI_COLUMNDEF *recinfo, *recinfo_pos;
 
222
  HA_KEYSEG *keyseg;
 
223
  TableShare *share= table_arg->getMutableShare();
 
224
  uint32_t options= share->db_options_in_use;
 
225
  if (!(memory::multi_malloc(false,
 
226
          recinfo_out, (share->sizeFields() * 2 + 2) * sizeof(MI_COLUMNDEF),
 
227
          keydef_out, share->sizeKeys() * sizeof(MI_KEYDEF),
 
228
          &keyseg, (share->key_parts + share->sizeKeys()) * sizeof(HA_KEYSEG),
 
229
          NULL)))
 
230
    return(HA_ERR_OUT_OF_MEM);
 
231
  keydef= *keydef_out;
 
232
  recinfo= *recinfo_out;
 
233
  for (i= 0; i < share->sizeKeys(); i++)
 
234
  {
 
235
    KeyInfo *pos= &table_arg->key_info[i];
 
236
    keydef[i].flag= ((uint16_t) pos->flags & (HA_NOSAME));
 
237
    keydef[i].key_alg= HA_KEY_ALG_BTREE;
 
238
    keydef[i].block_length= pos->block_size;
 
239
    keydef[i].seg= keyseg;
 
240
    keydef[i].keysegs= pos->key_parts;
 
241
    for (j= 0; j < pos->key_parts; j++)
 
242
    {
 
243
      Field *field= pos->key_part[j].field;
 
244
      type= field->key_type();
 
245
      keydef[i].seg[j].flag= pos->key_part[j].key_part_flag;
 
246
 
 
247
      if (options & HA_OPTION_PACK_KEYS ||
 
248
          (pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY |
 
249
                         HA_SPACE_PACK_USED)))
 
250
      {
 
251
        if (pos->key_part[j].length > 8 &&
 
252
            (type == HA_KEYTYPE_TEXT ||
 
253
             (type == HA_KEYTYPE_BINARY && !field->zero_pack())))
 
254
        {
 
255
          /* No blobs here */
 
256
          if (j == 0)
 
257
            keydef[i].flag|= HA_PACK_KEY;
 
258
          if ((((int) (pos->key_part[j].length - field->decimals())) >= 4))
 
259
            keydef[i].seg[j].flag|= HA_SPACE_PACK;
 
260
        }
 
261
        else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16))
 
262
          keydef[i].flag|= HA_BINARY_PACK_KEY;
 
263
      }
 
264
      keydef[i].seg[j].type= (int) type;
 
265
      keydef[i].seg[j].start= pos->key_part[j].offset;
 
266
      keydef[i].seg[j].length= pos->key_part[j].length;
 
267
      keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_end=
 
268
        keydef[i].seg[j].bit_length= 0;
 
269
      keydef[i].seg[j].bit_pos= 0;
 
270
      keydef[i].seg[j].language= field->charset()->number;
 
271
 
 
272
      if (field->null_ptr)
 
273
      {
 
274
        keydef[i].seg[j].null_bit= field->null_bit;
 
275
        keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
 
276
                                           (unsigned char*) table_arg->getInsertRecord());
 
277
      }
 
278
      else
 
279
      {
 
280
        keydef[i].seg[j].null_bit= 0;
 
281
        keydef[i].seg[j].null_pos= 0;
 
282
      }
 
283
      if (field->type() == DRIZZLE_TYPE_BLOB)
 
284
      {
 
285
        keydef[i].seg[j].flag|= HA_BLOB_PART;
 
286
        /* save number of bytes used to pack length */
 
287
        keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
 
288
                                            share->blob_ptr_size);
 
289
      }
 
290
    }
 
291
    keyseg+= pos->key_parts;
 
292
  }
 
293
  if (table_arg->found_next_number_field)
 
294
    keydef[share->next_number_index].flag|= HA_AUTO_KEY;
 
295
  record= table_arg->getInsertRecord();
 
296
  recpos= 0;
 
297
  recinfo_pos= recinfo;
 
298
  while (recpos < (uint) share->stored_rec_length)
 
299
  {
 
300
    Field **field, *found= 0;
 
301
    minpos= share->getRecordLength();
 
302
    length= 0;
 
303
 
 
304
    for (field= table_arg->getFields(); *field; field++)
 
305
    {
 
306
      if ((fieldpos= (*field)->offset(record)) >= recpos &&
 
307
          fieldpos <= minpos)
 
308
      {
 
309
        /* skip null fields */
 
310
        if (!(temp_length= (*field)->pack_length_in_rec()))
 
311
          continue; /* Skip null-fields */
 
312
        if (! found || fieldpos < minpos ||
 
313
            (fieldpos == minpos && temp_length < length))
 
314
        {
 
315
          minpos= fieldpos;
 
316
          found= *field;
 
317
          length= temp_length;
 
318
        }
 
319
      }
 
320
    }
 
321
    if (recpos != minpos)
 
322
    { // Reserved space (Null bits?)
 
323
      memset(recinfo_pos, 0, sizeof(*recinfo_pos));
 
324
      recinfo_pos->type= (int) FIELD_NORMAL;
 
325
      recinfo_pos++->length= (uint16_t) (minpos - recpos);
 
326
    }
 
327
    if (!found)
 
328
      break;
 
329
 
 
330
    if (found->flags & BLOB_FLAG)
 
331
      recinfo_pos->type= (int) FIELD_BLOB;
 
332
    else if (found->type() == DRIZZLE_TYPE_VARCHAR)
 
333
      recinfo_pos->type= FIELD_VARCHAR;
 
334
    else if (!(options & HA_OPTION_PACK_RECORD))
 
335
      recinfo_pos->type= (int) FIELD_NORMAL;
 
336
    else if (found->zero_pack())
 
337
      recinfo_pos->type= (int) FIELD_SKIP_ZERO;
 
338
    else
 
339
      recinfo_pos->type= (int) ((length <= 3) ?  FIELD_NORMAL : FIELD_SKIP_PRESPACE);
 
340
    if (found->null_ptr)
 
341
    {
 
342
      recinfo_pos->null_bit= found->null_bit;
 
343
      recinfo_pos->null_pos= (uint) (found->null_ptr -
 
344
                                     (unsigned char*) table_arg->getInsertRecord());
 
345
    }
 
346
    else
 
347
    {
 
348
      recinfo_pos->null_bit= 0;
 
349
      recinfo_pos->null_pos= 0;
 
350
    }
 
351
    (recinfo_pos++)->length= (uint16_t) length;
 
352
    recpos= minpos + length;
 
353
  }
 
354
  *records_out= (uint) (recinfo_pos - recinfo);
 
355
  return(0);
 
356
}
 
357
 
 
358
int ha_myisam::reset_auto_increment(uint64_t value)
 
359
{
 
360
  file->s->state.auto_increment= value;
 
361
  return 0;
 
362
}
 
363
 
 
364
/*
 
365
  Check for underlying table conformance
 
366
 
 
367
  SYNOPSIS
 
368
    check_definition()
 
369
      t1_keyinfo       in    First table key definition
 
370
      t1_recinfo       in    First table record definition
 
371
      t1_keys          in    Number of keys in first table
 
372
      t1_recs          in    Number of records in first table
 
373
      t2_keyinfo       in    Second table key definition
 
374
      t2_recinfo       in    Second table record definition
 
375
      t2_keys          in    Number of keys in second table
 
376
      t2_recs          in    Number of records in second table
 
377
      strict           in    Strict check switch
 
378
 
 
379
  DESCRIPTION
 
380
    This function compares two MyISAM definitions. By intention it was done
 
381
    to compare merge table definition against underlying table definition.
 
382
    It may also be used to compare dot-frm and MYI definitions of MyISAM
 
383
    table as well to compare different MyISAM table definitions.
 
384
 
 
385
    For merge table it is not required that number of keys in merge table
 
386
    must exactly match number of keys in underlying table. When calling this
 
387
    function for underlying table conformance check, 'strict' flag must be
 
388
    set to false, and converted merge definition must be passed as t1_*.
 
389
 
 
390
    Otherwise 'strict' flag must be set to 1 and it is not required to pass
 
391
    converted dot-frm definition as t1_*.
 
392
 
 
393
  RETURN VALUE
 
394
    0 - Equal definitions.
 
395
    1 - Different definitions.
 
396
 
 
397
  TODO
 
398
    - compare FULLTEXT keys;
 
399
    - compare SPATIAL keys;
 
400
    - compare FIELD_SKIP_ZERO which is converted to FIELD_NORMAL correctly
 
401
      (should be corretly detected in table2myisam).
 
402
*/
 
403
 
 
404
static int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
 
405
                            uint32_t t1_keys, uint32_t t1_recs,
 
406
                            MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
 
407
                            uint32_t t2_keys, uint32_t t2_recs, bool strict)
 
408
{
 
409
  uint32_t i, j;
 
410
  if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys))
 
411
  {
 
412
    return(1);
 
413
  }
 
414
  if (t1_recs != t2_recs)
 
415
  {
 
416
    return(1);
 
417
  }
 
418
  for (i= 0; i < t1_keys; i++)
 
419
  {
 
420
    HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg;
 
421
    HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg;
 
422
    if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs ||
 
423
        t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg)
 
424
    {
 
425
      return(1);
 
426
    }
 
427
    for (j=  t1_keyinfo[i].keysegs; j--;)
 
428
    {
 
429
      uint8_t t1_keysegs_j__type= t1_keysegs[j].type;
 
430
 
 
431
      /*
 
432
        Table migration from 4.1 to 5.1. In 5.1 a *TEXT key part is
 
433
        always HA_KEYTYPE_VARTEXT2. In 4.1 we had only the equivalent of
 
434
        HA_KEYTYPE_VARTEXT1. Since we treat both the same on MyISAM
 
435
        level, we can ignore a mismatch between these types.
 
436
      */
 
437
      if ((t1_keysegs[j].flag & HA_BLOB_PART) &&
 
438
          (t2_keysegs[j].flag & HA_BLOB_PART))
 
439
      {
 
440
        if ((t1_keysegs_j__type == HA_KEYTYPE_VARTEXT2) &&
 
441
            (t2_keysegs[j].type == HA_KEYTYPE_VARTEXT1))
 
442
          t1_keysegs_j__type= HA_KEYTYPE_VARTEXT1;
 
443
        else if ((t1_keysegs_j__type == HA_KEYTYPE_VARBINARY2) &&
 
444
                 (t2_keysegs[j].type == HA_KEYTYPE_VARBINARY1))
 
445
          t1_keysegs_j__type= HA_KEYTYPE_VARBINARY1;
 
446
      }
 
447
 
 
448
      if (t1_keysegs_j__type != t2_keysegs[j].type ||
 
449
          t1_keysegs[j].language != t2_keysegs[j].language ||
 
450
          t1_keysegs[j].null_bit != t2_keysegs[j].null_bit ||
 
451
          t1_keysegs[j].length != t2_keysegs[j].length)
 
452
      {
 
453
        return(1);
 
454
      }
 
455
    }
 
456
  }
 
457
  for (i= 0; i < t1_recs; i++)
 
458
  {
 
459
    MI_COLUMNDEF *t1_rec= &t1_recinfo[i];
 
460
    MI_COLUMNDEF *t2_rec= &t2_recinfo[i];
 
461
    /*
 
462
      FIELD_SKIP_ZERO can be changed to FIELD_NORMAL in mi_create,
 
463
      see NOTE1 in mi_create.c
 
464
    */
 
465
    if ((t1_rec->type != t2_rec->type &&
 
466
         !(t1_rec->type == (int) FIELD_SKIP_ZERO &&
 
467
           t1_rec->length == 1 &&
 
468
           t2_rec->type == (int) FIELD_NORMAL)) ||
 
469
        t1_rec->length != t2_rec->length ||
 
470
        t1_rec->null_bit != t2_rec->null_bit)
 
471
    {
 
472
      return(1);
 
473
    }
 
474
  }
 
475
  return(0);
 
476
}
 
477
 
 
478
 
 
479
volatile int *killed_ptr(MI_CHECK *param)
 
480
{
 
481
  /* In theory Unsafe conversion, but should be ok for now */
 
482
  return (int*) (((Session *)(param->session))->getKilledPtr());
 
483
}
 
484
 
 
485
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
 
486
{
 
487
  param->error_printed|=1;
 
488
  param->out_flag|= O_DATA_LOST;
 
489
  va_list args;
 
490
  va_start(args, fmt);
 
491
  mi_check_print_msg(param, "error", fmt, args);
 
492
  va_end(args);
 
493
}
 
494
 
 
495
void mi_check_print_info(MI_CHECK *param, const char *fmt,...)
 
496
{
 
497
  va_list args;
 
498
  va_start(args, fmt);
 
499
  mi_check_print_msg(param, "info", fmt, args);
 
500
  va_end(args);
 
501
}
 
502
 
 
503
void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
 
504
{
 
505
  param->warning_printed=1;
 
506
  param->out_flag|= O_DATA_LOST;
 
507
  va_list args;
 
508
  va_start(args, fmt);
 
509
  mi_check_print_msg(param, "warning", fmt, args);
 
510
  va_end(args);
 
511
}
 
512
 
 
513
/**
 
514
  Report list of threads (and queries) accessing a table, thread_id of a
 
515
  thread that detected corruption, ource file name and line number where
 
516
  this corruption was detected, optional extra information (string).
 
517
 
 
518
  This function is intended to be used when table corruption is detected.
 
519
 
 
520
  @param[in] file      MI_INFO object.
 
521
  @param[in] message   Optional error message.
 
522
  @param[in] sfile     Name of source file.
 
523
  @param[in] sline     Line number in source file.
 
524
 
 
525
  @return void
 
526
*/
 
527
 
 
528
void _mi_report_crashed(MI_INFO *file, const char *message,
 
529
                        const char *sfile, uint32_t sline)
 
530
{
 
531
  Session *cur_session;
 
532
  if ((cur_session= file->in_use))
 
533
    errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from thread_id=%"PRIu64", %s:%d"),
 
534
                    cur_session->thread_id,
 
535
                    sfile, sline);
 
536
  else
 
537
    errmsg_printf(ERRMSG_LVL_ERROR, _("Got an error from unknown thread, %s:%d"), sfile, sline);
 
538
  if (message)
 
539
    errmsg_printf(ERRMSG_LVL_ERROR, "%s", message);
 
540
  list<Session *>::iterator it= file->s->in_use->begin();
 
541
  while (it != file->s->in_use->end())
 
542
  {
 
543
    errmsg_printf(ERRMSG_LVL_ERROR, "%s", _("Unknown thread accessing table"));
 
544
    ++it;
 
545
  }
 
546
}
 
547
 
 
548
ha_myisam::ha_myisam(plugin::StorageEngine &engine_arg,
 
549
                     Table &table_arg)
 
550
  : Cursor(engine_arg, table_arg),
 
551
  file(0),
 
552
  can_enable_indexes(true),
 
553
  is_ordered(true)
 
554
{ }
 
555
 
 
556
Cursor *ha_myisam::clone(memory::Root *mem_root)
 
557
{
 
558
  ha_myisam *new_handler= static_cast <ha_myisam *>(Cursor::clone(mem_root));
 
559
  if (new_handler)
 
560
    new_handler->file->state= file->state;
 
561
  return new_handler;
 
562
}
 
563
 
 
564
const char *ha_myisam::index_type(uint32_t )
 
565
{
 
566
  return "BTREE";
 
567
}
 
568
 
 
569
/* Name is here without an extension */
 
570
int ha_myisam::doOpen(const drizzled::TableIdentifier &identifier, int mode, uint32_t test_if_locked)
 
571
{
 
572
  MI_KEYDEF *keyinfo;
 
573
  MI_COLUMNDEF *recinfo= 0;
 
574
  uint32_t recs;
 
575
  uint32_t i;
 
576
 
 
577
  /*
 
578
    If the user wants to have memory mapped data files, add an
 
579
    open_flag. Do not memory map temporary tables because they are
 
580
    expected to be inserted and thus extended a lot. Memory mapping is
 
581
    efficient for files that keep their size, but very inefficient for
 
582
    growing files. Using an open_flag instead of calling mi_extra(...
 
583
    HA_EXTRA_MMAP ...) after mi_open() has the advantage that the
 
584
    mapping is not repeated for every open, but just done on the initial
 
585
    open, when the MyISAM share is created. Everytime the server
 
586
    requires to open a new instance of a table it calls this method. We
 
587
    will always supply HA_OPEN_MMAP for a permanent table. However, the
 
588
    MyISAM storage engine will ignore this flag if this is a secondary
 
589
    open of a table that is in use by other threads already (if the
 
590
    MyISAM share exists already).
 
591
  */
 
592
  if (!(file= mi_open(identifier, mode, test_if_locked)))
 
593
    return (errno ? errno : -1);
 
594
 
 
595
  if (!getTable()->getShare()->getType()) /* No need to perform a check for tmp table */
 
596
  {
 
597
    if ((errno= table2myisam(getTable(), &keyinfo, &recinfo, &recs)))
 
598
    {
 
599
      goto err;
 
600
    }
 
601
    if (check_definition(keyinfo, recinfo, getTable()->getShare()->sizeKeys(), recs,
 
602
                         file->s->keyinfo, file->s->rec,
 
603
                         file->s->base.keys, file->s->base.fields, true))
 
604
    {
 
605
      errno= HA_ERR_CRASHED;
 
606
      goto err;
 
607
    }
 
608
  }
 
609
 
 
610
  assert(test_if_locked);
 
611
  if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
 
612
    mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0);
 
613
 
 
614
  info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
 
615
  if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
 
616
    mi_extra(file, HA_EXTRA_WAIT_LOCK, 0);
 
617
  if (!getTable()->getShare()->db_record_offset)
 
618
    is_ordered= false;
 
619
 
 
620
 
 
621
  keys_with_parts.reset();
 
622
  for (i= 0; i < getTable()->getShare()->sizeKeys(); i++)
 
623
  {
 
624
    getTable()->key_info[i].block_size= file->s->keyinfo[i].block_length;
 
625
 
 
626
    KeyPartInfo *kp= getTable()->key_info[i].key_part;
 
627
    KeyPartInfo *kp_end= kp + getTable()->key_info[i].key_parts;
 
628
    for (; kp != kp_end; kp++)
 
629
    {
 
630
      if (!kp->field->part_of_key.test(i))
 
631
      {
 
632
        keys_with_parts.set(i);
 
633
        break;
 
634
      }
 
635
    }
 
636
  }
 
637
  errno= 0;
 
638
  goto end;
 
639
 err:
 
640
  this->close();
 
641
 end:
 
642
  /*
 
643
    Both recinfo and keydef are allocated by multi_malloc(), thus only
 
644
    recinfo must be freed.
 
645
  */
 
646
  if (recinfo)
 
647
    free((unsigned char*) recinfo);
 
648
  return errno;
 
649
}
 
650
 
 
651
int ha_myisam::close(void)
 
652
{
 
653
  MI_INFO *tmp=file;
 
654
  file=0;
 
655
  return mi_close(tmp);
 
656
}
 
657
 
 
658
int ha_myisam::doInsertRecord(unsigned char *buf)
 
659
{
 
660
  /*
 
661
    If we have an auto_increment column and we are writing a changed row
 
662
    or a new row, then update the auto_increment value in the record.
 
663
  */
 
664
  if (getTable()->next_number_field && buf == getTable()->getInsertRecord())
 
665
  {
 
666
    int error;
 
667
    if ((error= update_auto_increment()))
 
668
      return error;
 
669
  }
 
670
  return mi_write(file,buf);
 
671
}
 
672
 
 
673
 
 
674
int ha_myisam::repair(Session *session, MI_CHECK &param, bool do_optimize)
 
675
{
 
676
  int error=0;
 
677
  uint32_t local_testflag= param.testflag;
 
678
  bool optimize_done= !do_optimize, statistics_done=0;
 
679
  const char *old_proc_info= session->get_proc_info();
 
680
  char fixed_name[FN_REFLEN];
 
681
  MYISAM_SHARE* share = file->s;
 
682
  ha_rows rows= file->state->records;
 
683
 
 
684
  /*
 
685
    Normally this method is entered with a properly opened table. If the
 
686
    repair fails, it can be repeated with more elaborate options. Under
 
687
    special circumstances it can happen that a repair fails so that it
 
688
    closed the data file and cannot re-open it. In this case file->dfile
 
689
    is set to -1. We must not try another repair without an open data
 
690
    file. (Bug #25289)
 
691
  */
 
692
  if (file->dfile == -1)
 
693
  {
 
694
    errmsg_printf(ERRMSG_LVL_INFO, "Retrying repair of: '%s' failed. "
 
695
                          "Please try REPAIR EXTENDED or myisamchk",
 
696
                          getTable()->getShare()->getPath());
 
697
    return(HA_ADMIN_FAILED);
 
698
  }
 
699
 
 
700
  param.db_name=    getTable()->getShare()->getSchemaName();
 
701
  param.table_name= getTable()->getAlias();
 
702
  param.tmpfile_createflag = O_RDWR | O_TRUNC;
 
703
  param.using_global_keycache = 1;
 
704
  param.session= session;
 
705
  param.out_flag= 0;
 
706
  param.sort_buffer_length= static_cast<size_t>(sort_buffer_size);
 
707
  strcpy(fixed_name,file->filename);
 
708
 
 
709
  // Don't lock tables if we have used LOCK Table
 
710
  if (mi_lock_database(file, getTable()->getShare()->getType() ? F_EXTRA_LCK : F_WRLCK))
 
711
  {
 
712
    mi_check_print_error(&param,ER(ER_CANT_LOCK),errno);
 
713
    return(HA_ADMIN_FAILED);
 
714
  }
 
715
 
 
716
  if (!do_optimize ||
 
717
      ((file->state->del || share->state.split != file->state->records) &&
 
718
       (!(param.testflag & T_QUICK) ||
 
719
        !(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))))
 
720
  {
 
721
    uint64_t key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
 
722
                        mi_get_mask_all_keys_active(share->base.keys) :
 
723
                        share->state.key_map);
 
724
    uint32_t testflag=param.testflag;
 
725
    if (mi_test_if_sort_rep(file,file->state->records,key_map,0) &&
 
726
        (local_testflag & T_REP_BY_SORT))
 
727
    {
 
728
      local_testflag|= T_STATISTICS;
 
729
      param.testflag|= T_STATISTICS;            // We get this for free
 
730
      statistics_done=1;
 
731
      {
 
732
        session->set_proc_info("Repair by sorting");
 
733
        error = mi_repair_by_sort(&param, file, fixed_name,
 
734
            param.testflag & T_QUICK);
 
735
      }
 
736
    }
 
737
    else
 
738
    {
 
739
      session->set_proc_info("Repair with keycache");
 
740
      param.testflag &= ~T_REP_BY_SORT;
 
741
      error=  mi_repair(&param, file, fixed_name,
 
742
                        param.testflag & T_QUICK);
 
743
    }
 
744
    param.testflag=testflag;
 
745
    optimize_done=1;
 
746
  }
 
747
  if (!error)
 
748
  {
 
749
    if ((local_testflag & T_SORT_INDEX) &&
 
750
        (share->state.changed & STATE_NOT_SORTED_PAGES))
 
751
    {
 
752
      optimize_done=1;
 
753
      session->set_proc_info("Sorting index");
 
754
      error=mi_sort_index(&param,file,fixed_name);
 
755
    }
 
756
    if (!statistics_done && (local_testflag & T_STATISTICS))
 
757
    {
 
758
      if (share->state.changed & STATE_NOT_ANALYZED)
 
759
      {
 
760
        optimize_done=1;
 
761
        session->set_proc_info("Analyzing");
 
762
        error = chk_key(&param, file);
 
763
      }
 
764
      else
 
765
        local_testflag&= ~T_STATISTICS;         // Don't update statistics
 
766
    }
 
767
  }
 
768
  session->set_proc_info("Saving state");
 
769
  if (!error)
 
770
  {
 
771
    if ((share->state.changed & STATE_CHANGED) || mi_is_crashed(file))
 
772
    {
 
773
      share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED |
 
774
                               STATE_CRASHED_ON_REPAIR);
 
775
      file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
 
776
    }
 
777
    /*
 
778
      the following 'if', thought conceptually wrong,
 
779
      is a useful optimization nevertheless.
 
780
    */
 
781
    if (file->state != &file->s->state.state)
 
782
      file->s->state.state = *file->state;
 
783
    if (file->s->base.auto_key)
 
784
      update_auto_increment_key(&param, file, 1);
 
785
    if (optimize_done)
 
786
      error = update_state_info(&param, file,
 
787
                                UPDATE_TIME | UPDATE_OPEN_COUNT |
 
788
                                (local_testflag &
 
789
                                 T_STATISTICS ? UPDATE_STAT : 0));
 
790
    info(HA_STATUS_NO_LOCK | HA_STATUS_TIME | HA_STATUS_VARIABLE |
 
791
         HA_STATUS_CONST);
 
792
    if (rows != file->state->records && ! (param.testflag & T_VERY_SILENT))
 
793
    {
 
794
      char llbuff[22],llbuff2[22];
 
795
      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));
 
798
    }
 
799
  }
 
800
  else
 
801
  {
 
802
    mi_mark_crashed_on_repair(file);
 
803
    file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
 
804
    update_state_info(&param, file, 0);
 
805
  }
 
806
  session->set_proc_info(old_proc_info);
 
807
  mi_lock_database(file,F_UNLCK);
 
808
 
 
809
  return(error ? HA_ADMIN_FAILED :
 
810
              !optimize_done ? HA_ADMIN_ALREADY_DONE : HA_ADMIN_OK);
 
811
}
 
812
 
 
813
 
 
814
/*
 
815
  Disable indexes, making it persistent if requested.
 
816
 
 
817
  SYNOPSIS
 
818
    disable_indexes()
 
819
    mode        mode of operation:
 
820
                HA_KEY_SWITCH_NONUNIQ      disable all non-unique keys
 
821
                HA_KEY_SWITCH_ALL          disable all keys
 
822
                HA_KEY_SWITCH_NONUNIQ_SAVE dis. non-uni. and make persistent
 
823
                HA_KEY_SWITCH_ALL_SAVE     dis. all keys and make persistent
 
824
 
 
825
  IMPLEMENTATION
 
826
    HA_KEY_SWITCH_NONUNIQ       is not implemented.
 
827
    HA_KEY_SWITCH_ALL_SAVE      is not implemented.
 
828
 
 
829
  RETURN
 
830
    0  ok
 
831
    HA_ERR_WRONG_COMMAND  mode not implemented.
 
832
*/
 
833
 
 
834
int ha_myisam::disable_indexes(uint32_t mode)
 
835
{
 
836
  int error;
 
837
 
 
838
  if (mode == HA_KEY_SWITCH_ALL)
 
839
  {
 
840
    /* call a storage engine function to switch the key map */
 
841
    error= mi_disable_indexes(file);
 
842
  }
 
843
  else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
 
844
  {
 
845
    mi_extra(file, HA_EXTRA_NO_KEYS, 0);
 
846
    info(HA_STATUS_CONST);                        // Read new key info
 
847
    error= 0;
 
848
  }
 
849
  else
 
850
  {
 
851
    /* mode not implemented */
 
852
    error= HA_ERR_WRONG_COMMAND;
 
853
  }
 
854
  return error;
 
855
}
 
856
 
 
857
 
 
858
/*
 
859
  Enable indexes, making it persistent if requested.
 
860
 
 
861
  SYNOPSIS
 
862
    enable_indexes()
 
863
    mode        mode of operation:
 
864
                HA_KEY_SWITCH_NONUNIQ      enable all non-unique keys
 
865
                HA_KEY_SWITCH_ALL          enable all keys
 
866
                HA_KEY_SWITCH_NONUNIQ_SAVE en. non-uni. and make persistent
 
867
                HA_KEY_SWITCH_ALL_SAVE     en. all keys and make persistent
 
868
 
 
869
  DESCRIPTION
 
870
    Enable indexes, which might have been disabled by disable_index() before.
 
871
    The modes without _SAVE work only if both data and indexes are empty,
 
872
    since the MyISAM repair would enable them persistently.
 
873
    To be sure in these cases, call Cursor::delete_all_rows() before.
 
874
 
 
875
  IMPLEMENTATION
 
876
    HA_KEY_SWITCH_NONUNIQ       is not implemented.
 
877
    HA_KEY_SWITCH_ALL_SAVE      is not implemented.
 
878
 
 
879
  RETURN
 
880
    0  ok
 
881
    !=0  Error, among others:
 
882
    HA_ERR_CRASHED  data or index is non-empty. Delete all rows and retry.
 
883
    HA_ERR_WRONG_COMMAND  mode not implemented.
 
884
*/
 
885
 
 
886
int ha_myisam::enable_indexes(uint32_t mode)
 
887
{
 
888
  int error;
 
889
 
 
890
  if (mi_is_all_keys_active(file->s->state.key_map, file->s->base.keys))
 
891
  {
 
892
    /* All indexes are enabled already. */
 
893
    return 0;
 
894
  }
 
895
 
 
896
  if (mode == HA_KEY_SWITCH_ALL)
 
897
  {
 
898
    error= mi_enable_indexes(file);
 
899
    /*
 
900
       Do not try to repair on error,
 
901
       as this could make the enabled state persistent,
 
902
       but mode==HA_KEY_SWITCH_ALL forbids it.
 
903
    */
 
904
  }
 
905
  else if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE)
 
906
  {
 
907
    Session *session= getTable()->in_use;
 
908
    boost::scoped_ptr<MI_CHECK> param_ap(new MI_CHECK);
 
909
    MI_CHECK &param= *param_ap.get();
 
910
    const char *save_proc_info= session->get_proc_info();
 
911
    session->set_proc_info("Creating index");
 
912
    myisamchk_init(&param);
 
913
    param.op_name= "recreating_index";
 
914
    param.testflag= (T_SILENT | T_REP_BY_SORT | T_QUICK |
 
915
                     T_CREATE_MISSING_KEYS);
 
916
    param.myf_rw&= ~MY_WAIT_IF_FULL;
 
917
    param.sort_buffer_length=  static_cast<size_t>(sort_buffer_size);
 
918
    param.stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
 
919
    if ((error= (repair(session,param,0) != HA_ADMIN_OK)) && param.retry_repair)
 
920
    {
 
921
      errmsg_printf(ERRMSG_LVL_WARN, "Warning: Enabling keys got errno %d on %s.%s, retrying",
 
922
                        errno, param.db_name, param.table_name);
 
923
      /* Repairing by sort failed. Now try standard repair method. */
 
924
      param.testflag&= ~(T_REP_BY_SORT | T_QUICK);
 
925
      error= (repair(session,param,0) != HA_ADMIN_OK);
 
926
      /*
 
927
        If the standard repair succeeded, clear all error messages which
 
928
        might have been set by the first repair. They can still be seen
 
929
        with SHOW WARNINGS then.
 
930
      */
 
931
      if (! error)
 
932
        session->clear_error();
 
933
    }
 
934
    info(HA_STATUS_CONST);
 
935
    session->set_proc_info(save_proc_info);
 
936
  }
 
937
  else
 
938
  {
 
939
    /* mode not implemented */
 
940
    error= HA_ERR_WRONG_COMMAND;
 
941
  }
 
942
  return error;
 
943
}
 
944
 
 
945
 
 
946
/*
 
947
  Test if indexes are disabled.
 
948
 
 
949
 
 
950
  SYNOPSIS
 
951
    indexes_are_disabled()
 
952
      no parameters
 
953
 
 
954
 
 
955
  RETURN
 
956
    0  indexes are not disabled
 
957
    1  all indexes are disabled
 
958
   [2  non-unique indexes are disabled - NOT YET IMPLEMENTED]
 
959
*/
 
960
 
 
961
int ha_myisam::indexes_are_disabled(void)
 
962
{
 
963
 
 
964
  return mi_indexes_are_disabled(file);
 
965
}
 
966
 
 
967
 
 
968
/*
 
969
  prepare for a many-rows insert operation
 
970
  e.g. - disable indexes (if they can be recreated fast) or
 
971
  activate special bulk-insert optimizations
 
972
 
 
973
  SYNOPSIS
 
974
    start_bulk_insert(rows)
 
975
    rows        Rows to be inserted
 
976
                0 if we don't know
 
977
 
 
978
  NOTICE
 
979
    Do not forget to call end_bulk_insert() later!
 
980
*/
 
981
 
 
982
void ha_myisam::start_bulk_insert(ha_rows rows)
 
983
{
 
984
  Session *session= getTable()->in_use;
 
985
  ulong size= session->variables.read_buff_size;
 
986
 
 
987
  /* don't enable row cache if too few rows */
 
988
  if (! rows || (rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE))
 
989
    mi_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &size);
 
990
 
 
991
  can_enable_indexes= mi_is_all_keys_active(file->s->state.key_map,
 
992
                                            file->s->base.keys);
 
993
 
 
994
  /*
 
995
    Only disable old index if the table was empty and we are inserting
 
996
    a lot of rows.
 
997
    We should not do this for only a few rows as this is slower and
 
998
    we don't want to update the key statistics based of only a few rows.
 
999
  */
 
1000
  if (file->state->records == 0 && can_enable_indexes &&
 
1001
      (!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES))
 
1002
    mi_disable_non_unique_index(file,rows);
 
1003
  else
 
1004
    if (!file->bulk_insert &&
 
1005
        (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT))
 
1006
    {
 
1007
      mi_init_bulk_insert(file,
 
1008
                          (size_t)session->variables.bulk_insert_buff_size,
 
1009
                          rows);
 
1010
    }
 
1011
}
 
1012
 
 
1013
/*
 
1014
  end special bulk-insert optimizations,
 
1015
  which have been activated by start_bulk_insert().
 
1016
 
 
1017
  SYNOPSIS
 
1018
    end_bulk_insert()
 
1019
    no arguments
 
1020
 
 
1021
  RETURN
 
1022
    0     OK
 
1023
    != 0  Error
 
1024
*/
 
1025
 
 
1026
int ha_myisam::end_bulk_insert()
 
1027
{
 
1028
  mi_end_bulk_insert(file);
 
1029
  int err=mi_extra(file, HA_EXTRA_NO_CACHE, 0);
 
1030
  return err ? err : can_enable_indexes ?
 
1031
                     enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE) : 0;
 
1032
}
 
1033
 
 
1034
 
 
1035
 
 
1036
int ha_myisam::doUpdateRecord(const unsigned char *old_data, unsigned char *new_data)
 
1037
{
 
1038
  return mi_update(file,old_data,new_data);
 
1039
}
 
1040
 
 
1041
int ha_myisam::doDeleteRecord(const unsigned char *buf)
 
1042
{
 
1043
  return mi_delete(file,buf);
 
1044
}
 
1045
 
 
1046
 
 
1047
int ha_myisam::doStartIndexScan(uint32_t idx, bool )
 
1048
{
 
1049
  active_index=idx;
 
1050
  //in_range_read= false;
 
1051
  return 0;
 
1052
}
 
1053
 
 
1054
 
 
1055
int ha_myisam::doEndIndexScan()
 
1056
{
 
1057
  active_index=MAX_KEY;
 
1058
  return 0;
 
1059
}
 
1060
 
 
1061
 
 
1062
int ha_myisam::index_read_map(unsigned char *buf, const unsigned char *key,
 
1063
                              key_part_map keypart_map,
 
1064
                              enum ha_rkey_function find_flag)
 
1065
{
 
1066
  assert(inited==INDEX);
 
1067
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
1068
  int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
 
1069
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1070
  return error;
 
1071
}
 
1072
 
 
1073
int ha_myisam::index_read_idx_map(unsigned char *buf, uint32_t index, const unsigned char *key,
 
1074
                                  key_part_map keypart_map,
 
1075
                                  enum ha_rkey_function find_flag)
 
1076
{
 
1077
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
1078
  int error=mi_rkey(file, buf, index, key, keypart_map, find_flag);
 
1079
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1080
  return error;
 
1081
}
 
1082
 
 
1083
int ha_myisam::index_read_last_map(unsigned char *buf, const unsigned char *key,
 
1084
                                   key_part_map keypart_map)
 
1085
{
 
1086
  assert(inited==INDEX);
 
1087
  ha_statistic_increment(&system_status_var::ha_read_key_count);
 
1088
  int error=mi_rkey(file, buf, active_index, key, keypart_map,
 
1089
                    HA_READ_PREFIX_LAST);
 
1090
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1091
  return(error);
 
1092
}
 
1093
 
 
1094
int ha_myisam::index_next(unsigned char *buf)
 
1095
{
 
1096
  assert(inited==INDEX);
 
1097
  ha_statistic_increment(&system_status_var::ha_read_next_count);
 
1098
  int error=mi_rnext(file,buf,active_index);
 
1099
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1100
  return error;
 
1101
}
 
1102
 
 
1103
int ha_myisam::index_prev(unsigned char *buf)
 
1104
{
 
1105
  assert(inited==INDEX);
 
1106
  ha_statistic_increment(&system_status_var::ha_read_prev_count);
 
1107
  int error=mi_rprev(file,buf, active_index);
 
1108
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1109
  return error;
 
1110
}
 
1111
 
 
1112
int ha_myisam::index_first(unsigned char *buf)
 
1113
{
 
1114
  assert(inited==INDEX);
 
1115
  ha_statistic_increment(&system_status_var::ha_read_first_count);
 
1116
  int error=mi_rfirst(file, buf, active_index);
 
1117
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1118
  return error;
 
1119
}
 
1120
 
 
1121
int ha_myisam::index_last(unsigned char *buf)
 
1122
{
 
1123
  assert(inited==INDEX);
 
1124
  ha_statistic_increment(&system_status_var::ha_read_last_count);
 
1125
  int error=mi_rlast(file, buf, active_index);
 
1126
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1127
  return error;
 
1128
}
 
1129
 
 
1130
int ha_myisam::index_next_same(unsigned char *buf,
 
1131
                               const unsigned char *,
 
1132
                               uint32_t )
 
1133
{
 
1134
  int error;
 
1135
  assert(inited==INDEX);
 
1136
  ha_statistic_increment(&system_status_var::ha_read_next_count);
 
1137
  do
 
1138
  {
 
1139
    error= mi_rnext_same(file,buf);
 
1140
  } while (error == HA_ERR_RECORD_DELETED);
 
1141
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1142
  return error;
 
1143
}
 
1144
 
 
1145
int ha_myisam::read_range_first(const key_range *start_key,
 
1146
                                const key_range *end_key,
 
1147
                                bool eq_range_arg,
 
1148
                                bool sorted /* ignored */)
 
1149
{
 
1150
  int res;
 
1151
  //if (!eq_range_arg)
 
1152
  //  in_range_read= true;
 
1153
 
 
1154
  res= Cursor::read_range_first(start_key, end_key, eq_range_arg, sorted);
 
1155
 
 
1156
  //if (res)
 
1157
  //  in_range_read= false;
 
1158
  return res;
 
1159
}
 
1160
 
 
1161
 
 
1162
int ha_myisam::read_range_next()
 
1163
{
 
1164
  int res= Cursor::read_range_next();
 
1165
  //if (res)
 
1166
  //  in_range_read= false;
 
1167
  return res;
 
1168
}
 
1169
 
 
1170
 
 
1171
int ha_myisam::doStartTableScan(bool scan)
 
1172
{
 
1173
  if (scan)
 
1174
    return mi_scan_init(file);
 
1175
  return mi_reset(file);                        // Free buffers
 
1176
}
 
1177
 
 
1178
int ha_myisam::rnd_next(unsigned char *buf)
 
1179
{
 
1180
  ha_statistic_increment(&system_status_var::ha_read_rnd_next_count);
 
1181
  int error=mi_scan(file, buf);
 
1182
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1183
  return error;
 
1184
}
 
1185
 
 
1186
int ha_myisam::rnd_pos(unsigned char *buf, unsigned char *pos)
 
1187
{
 
1188
  ha_statistic_increment(&system_status_var::ha_read_rnd_count);
 
1189
  int error=mi_rrnd(file, buf, internal::my_get_ptr(pos,ref_length));
 
1190
  getTable()->status=error ? STATUS_NOT_FOUND: 0;
 
1191
  return error;
 
1192
}
 
1193
 
 
1194
 
 
1195
void ha_myisam::position(const unsigned char *)
 
1196
{
 
1197
  internal::my_off_t row_position= mi_position(file);
 
1198
  internal::my_store_ptr(ref, ref_length, row_position);
 
1199
}
 
1200
 
 
1201
int ha_myisam::info(uint32_t flag)
 
1202
{
 
1203
  MI_ISAMINFO misam_info;
 
1204
  char name_buff[FN_REFLEN];
 
1205
 
 
1206
  (void) mi_status(file,&misam_info,flag);
 
1207
  if (flag & HA_STATUS_VARIABLE)
 
1208
  {
 
1209
    stats.records=           misam_info.records;
 
1210
    stats.deleted=           misam_info.deleted;
 
1211
    stats.data_file_length=  misam_info.data_file_length;
 
1212
    stats.index_file_length= misam_info.index_file_length;
 
1213
    stats.delete_length=     misam_info.delete_length;
 
1214
    stats.check_time=        misam_info.check_time;
 
1215
    stats.mean_rec_length=   misam_info.mean_reclength;
 
1216
  }
 
1217
  if (flag & HA_STATUS_CONST)
 
1218
  {
 
1219
    TableShare *share= getTable()->getMutableShare();
 
1220
    stats.max_data_file_length=  misam_info.max_data_file_length;
 
1221
    stats.max_index_file_length= misam_info.max_index_file_length;
 
1222
    stats.create_time= misam_info.create_time;
 
1223
    ref_length= misam_info.reflength;
 
1224
    share->db_options_in_use= misam_info.options;
 
1225
    stats.block_size= myisam_key_cache_block_size;        /* record block size */
 
1226
 
 
1227
    set_prefix(share->keys_in_use, share->sizeKeys());
 
1228
    /*
 
1229
     * Due to bug 394932 (32-bit solaris build failure), we need
 
1230
     * to convert the uint64_t key_map member of the misam_info
 
1231
     * structure in to a std::bitset so that we can logically and
 
1232
     * it with the share->key_in_use key_map.
 
1233
     */
 
1234
    ostringstream ostr;
 
1235
    string binary_key_map;
 
1236
    uint64_t num= misam_info.key_map;
 
1237
    /*
 
1238
     * Convert the uint64_t to a binary
 
1239
     * string representation of it.
 
1240
     */
 
1241
    while (num > 0)
 
1242
    {
 
1243
      uint64_t bin_digit= num % 2;
 
1244
      ostr << bin_digit;
 
1245
      num/= 2;
 
1246
    }
 
1247
    binary_key_map.append(ostr.str());
 
1248
    /*
 
1249
     * Now we have the binary string representation of the
 
1250
     * flags, we need to fill that string representation out
 
1251
     * with the appropriate number of bits. This is needed
 
1252
     * since key_map is declared as a std::bitset of a certain bit
 
1253
     * width that depends on the MAX_INDEXES variable. 
 
1254
     */
 
1255
    if (MAX_INDEXES <= 64)
 
1256
    {
 
1257
      size_t len= 72 - binary_key_map.length();
 
1258
      string all_zeros(len, '0');
 
1259
      binary_key_map.insert(binary_key_map.begin(),
 
1260
                            all_zeros.begin(),
 
1261
                            all_zeros.end());
 
1262
    }
 
1263
    else
 
1264
    {
 
1265
      size_t len= (MAX_INDEXES + 7) / 8 * 8;
 
1266
      string all_zeros(len, '0');
 
1267
      binary_key_map.insert(binary_key_map.begin(),
 
1268
                            all_zeros.begin(),
 
1269
                            all_zeros.end());
 
1270
    }
 
1271
    key_map tmp_map(binary_key_map);
 
1272
    share->keys_in_use&= tmp_map;
 
1273
    share->keys_for_keyread&= share->keys_in_use;
 
1274
    share->db_record_offset= misam_info.record_offset;
 
1275
    if (share->key_parts)
 
1276
      memcpy(getTable()->key_info[0].rec_per_key,
 
1277
             misam_info.rec_per_key,
 
1278
             sizeof(getTable()->key_info[0].rec_per_key)*share->key_parts);
 
1279
    assert(share->getType() != message::Table::STANDARD);
 
1280
 
 
1281
   /*
 
1282
     Set data_file_name and index_file_name to point at the symlink value
 
1283
     if table is symlinked (Ie;  Real name is not same as generated name)
 
1284
   */
 
1285
    data_file_name= index_file_name= 0;
 
1286
    internal::fn_format(name_buff, file->filename, "", MI_NAME_DEXT,
 
1287
              MY_APPEND_EXT | MY_UNPACK_FILENAME);
 
1288
    if (strcmp(name_buff, misam_info.data_file_name))
 
1289
      data_file_name=misam_info.data_file_name;
 
1290
    internal::fn_format(name_buff, file->filename, "", MI_NAME_IEXT,
 
1291
              MY_APPEND_EXT | MY_UNPACK_FILENAME);
 
1292
    if (strcmp(name_buff, misam_info.index_file_name))
 
1293
      index_file_name=misam_info.index_file_name;
 
1294
  }
 
1295
  if (flag & HA_STATUS_ERRKEY)
 
1296
  {
 
1297
    errkey  = misam_info.errkey;
 
1298
    internal::my_store_ptr(dup_ref, ref_length, misam_info.dupp_key_pos);
 
1299
  }
 
1300
  if (flag & HA_STATUS_TIME)
 
1301
    stats.update_time = misam_info.update_time;
 
1302
  if (flag & HA_STATUS_AUTO)
 
1303
    stats.auto_increment_value= misam_info.auto_increment;
 
1304
 
 
1305
  return 0;
 
1306
}
 
1307
 
 
1308
 
 
1309
int ha_myisam::extra(enum ha_extra_function operation)
 
1310
{
 
1311
  return mi_extra(file, operation, 0);
 
1312
}
 
1313
 
 
1314
int ha_myisam::reset(void)
 
1315
{
 
1316
  return mi_reset(file);
 
1317
}
 
1318
 
 
1319
/* To be used with WRITE_CACHE and EXTRA_CACHE */
 
1320
 
 
1321
int ha_myisam::extra_opt(enum ha_extra_function operation, uint32_t cache_size)
 
1322
{
 
1323
  return mi_extra(file, operation, (void*) &cache_size);
 
1324
}
 
1325
 
 
1326
int ha_myisam::delete_all_rows()
 
1327
{
 
1328
  return mi_delete_all_rows(file);
 
1329
}
 
1330
 
 
1331
int MyisamEngine::doDropTable(Session &session,
 
1332
                              const TableIdentifier &identifier)
 
1333
{
 
1334
  session.getMessageCache().removeTableMessage(identifier);
 
1335
 
 
1336
  return mi_delete_table(identifier.getPath().c_str());
 
1337
}
 
1338
 
 
1339
 
 
1340
int ha_myisam::external_lock(Session *session, int lock_type)
 
1341
{
 
1342
  file->in_use= session;
 
1343
  return mi_lock_database(file, !getTable()->getShare()->getType() ?
 
1344
                          lock_type : ((lock_type == F_UNLCK) ?
 
1345
                                       F_UNLCK : F_EXTRA_LCK));
 
1346
}
 
1347
 
 
1348
int MyisamEngine::doCreateTable(Session &session,
 
1349
                                Table& table_arg,
 
1350
                                const TableIdentifier &identifier,
 
1351
                                message::Table& create_proto)
 
1352
{
 
1353
  int error;
 
1354
  uint32_t create_flags= 0, create_records;
 
1355
  char buff[FN_REFLEN];
 
1356
  MI_KEYDEF *keydef;
 
1357
  MI_COLUMNDEF *recinfo;
 
1358
  MI_CREATE_INFO create_info;
 
1359
  TableShare *share= table_arg.getMutableShare();
 
1360
  uint32_t options= share->db_options_in_use;
 
1361
  if ((error= table2myisam(&table_arg, &keydef, &recinfo, &create_records)))
 
1362
    return(error);
 
1363
  memset(&create_info, 0, sizeof(create_info));
 
1364
  create_info.max_rows= create_proto.options().max_rows();
 
1365
  create_info.reloc_rows= create_proto.options().min_rows();
 
1366
  create_info.with_auto_increment= share->next_number_key_offset == 0;
 
1367
  create_info.auto_increment= (create_proto.options().has_auto_increment_value() ?
 
1368
                               create_proto.options().auto_increment_value() -1 :
 
1369
                               (uint64_t) 0);
 
1370
  create_info.data_file_length= (create_proto.options().max_rows() *
 
1371
                                 create_proto.options().avg_row_length());
 
1372
  create_info.data_file_name= NULL;
 
1373
  create_info.index_file_name=  NULL;
 
1374
  create_info.language= share->table_charset->number;
 
1375
 
 
1376
  if (create_proto.type() == message::Table::TEMPORARY)
 
1377
    create_flags|= HA_CREATE_TMP_TABLE;
 
1378
  if (options & HA_OPTION_PACK_RECORD)
 
1379
    create_flags|= HA_PACK_RECORD;
 
1380
 
 
1381
  /* TODO: Check that the following internal::fn_format is really needed */
 
1382
  error= mi_create(internal::fn_format(buff, identifier.getPath().c_str(), "", "",
 
1383
                                       MY_UNPACK_FILENAME|MY_APPEND_EXT),
 
1384
                   share->sizeKeys(), keydef,
 
1385
                   create_records, recinfo,
 
1386
                   0, (MI_UNIQUEDEF*) 0,
 
1387
                   &create_info, create_flags);
 
1388
  free((unsigned char*) recinfo);
 
1389
 
 
1390
  session.getMessageCache().storeTableMessage(identifier, create_proto);
 
1391
 
 
1392
  return error;
 
1393
}
 
1394
 
 
1395
 
 
1396
int MyisamEngine::doRenameTable(Session &session, const TableIdentifier &from, const TableIdentifier &to)
 
1397
{
 
1398
  session.getMessageCache().renameTableMessage(from, to);
 
1399
 
 
1400
  return mi_rename(from.getPath().c_str(), to.getPath().c_str());
 
1401
}
 
1402
 
 
1403
 
 
1404
void ha_myisam::get_auto_increment(uint64_t ,
 
1405
                                   uint64_t ,
 
1406
                                   uint64_t ,
 
1407
                                   uint64_t *first_value,
 
1408
                                   uint64_t *nb_reserved_values)
 
1409
{
 
1410
  uint64_t nr;
 
1411
  int error;
 
1412
  unsigned char key[MI_MAX_KEY_LENGTH];
 
1413
 
 
1414
  if (!getTable()->getShare()->next_number_key_offset)
 
1415
  {                                             // Autoincrement at key-start
 
1416
    ha_myisam::info(HA_STATUS_AUTO);
 
1417
    *first_value= stats.auto_increment_value;
 
1418
    /* MyISAM has only table-level lock, so reserves to +inf */
 
1419
    *nb_reserved_values= UINT64_MAX;
 
1420
    return;
 
1421
  }
 
1422
 
 
1423
  /* it's safe to call the following if bulk_insert isn't on */
 
1424
  mi_flush_bulk_insert(file, getTable()->getShare()->next_number_index);
 
1425
 
 
1426
  (void) extra(HA_EXTRA_KEYREAD);
 
1427
  key_copy(key, getTable()->getInsertRecord(),
 
1428
           &getTable()->key_info[getTable()->getShare()->next_number_index],
 
1429
           getTable()->getShare()->next_number_key_offset);
 
1430
  error= mi_rkey(file, getTable()->getUpdateRecord(), (int) getTable()->getShare()->next_number_index,
 
1431
                 key, make_prev_keypart_map(getTable()->getShare()->next_number_keypart),
 
1432
                 HA_READ_PREFIX_LAST);
 
1433
  if (error)
 
1434
    nr= 1;
 
1435
  else
 
1436
  {
 
1437
    /* Get data from getUpdateRecord() */
 
1438
    nr= ((uint64_t) getTable()->next_number_field->
 
1439
         val_int_offset(getTable()->getShare()->rec_buff_length)+1);
 
1440
  }
 
1441
  extra(HA_EXTRA_NO_KEYREAD);
 
1442
  *first_value= nr;
 
1443
  /*
 
1444
    MySQL needs to call us for next row: assume we are inserting ("a",null)
 
1445
    here, we return 3, and next this statement will want to insert ("b",null):
 
1446
    there is no reason why ("b",3+1) would be the good row to insert: maybe it
 
1447
    already exists, maybe 3+1 is too large...
 
1448
  */
 
1449
  *nb_reserved_values= 1;
 
1450
}
 
1451
 
 
1452
 
 
1453
/*
 
1454
  Find out how many rows there is in the given range
 
1455
 
 
1456
  SYNOPSIS
 
1457
    records_in_range()
 
1458
    inx                 Index to use
 
1459
    min_key             Start of range.  Null pointer if from first key
 
1460
    max_key             End of range. Null pointer if to last key
 
1461
 
 
1462
  NOTES
 
1463
    min_key.flag can have one of the following values:
 
1464
      HA_READ_KEY_EXACT         Include the key in the range
 
1465
      HA_READ_AFTER_KEY         Don't include key in range
 
1466
 
 
1467
    max_key.flag can have one of the following values:
 
1468
      HA_READ_BEFORE_KEY        Don't include key in range
 
1469
      HA_READ_AFTER_KEY         Include all 'end_key' values in the range
 
1470
 
 
1471
  RETURN
 
1472
   HA_POS_ERROR         Something is wrong with the index tree.
 
1473
   0                    There is no matching keys in the given range
 
1474
   number > 0           There is approximately 'number' matching rows in
 
1475
                        the range.
 
1476
*/
 
1477
 
 
1478
ha_rows ha_myisam::records_in_range(uint32_t inx, key_range *min_key,
 
1479
                                    key_range *max_key)
 
1480
{
 
1481
  return (ha_rows) mi_records_in_range(file, (int) inx, min_key, max_key);
 
1482
}
 
1483
 
 
1484
 
 
1485
uint32_t ha_myisam::checksum() const
 
1486
{
 
1487
  return (uint)file->state->checksum;
 
1488
}
 
1489
 
 
1490
static int myisam_init(module::Context &context)
 
1491
 
1492
  context.add(new MyisamEngine(engine_name));
 
1493
  context.registerVariable(new sys_var_constrained_value<size_t>("sort-buffer-size",
 
1494
                                                                 sort_buffer_size));
 
1495
  context.registerVariable(new sys_var_uint64_t_ptr("max_sort_file_size",
 
1496
                                                    &max_sort_file_size,
 
1497
                                                    context.getOptions()["max-sort-file-size"].as<uint64_t>()));
 
1498
 
 
1499
  return 0;
 
1500
}
 
1501
 
 
1502
 
 
1503
static void init_options(drizzled::module::option_context &context)
 
1504
{
 
1505
  context("max-sort-file-size",
 
1506
          po::value<uint64_t>(&max_sort_file_size)->default_value(INT32_MAX),
 
1507
          N_("Don't use the fast sort index method to created index if the temporary file would get bigger than this."));
 
1508
  context("sort-buffer-size",
 
1509
          po::value<sort_buffer_constraint>(&sort_buffer_size)->default_value(8192*1024),
 
1510
          N_("The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE."));
 
1511
}
 
1512
 
 
1513
 
 
1514
DRIZZLE_DECLARE_PLUGIN
 
1515
{
 
1516
  DRIZZLE_VERSION_ID,
 
1517
  "MyISAM",
 
1518
  "2.0",
 
1519
  "MySQL AB",
 
1520
  "Default engine as of MySQL 3.23 with great performance",
 
1521
  PLUGIN_LICENSE_GPL,
 
1522
  myisam_init, /* Plugin Init */
 
1523
  NULL,           /* system variables */
 
1524
  init_options                        /* config options                  */
 
1525
}
 
1526
DRIZZLE_DECLARE_PLUGIN_END;